-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathliz.reb
272 lines (226 loc) · 5.49 KB
/
liz.reb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
REBOL [
Title: "LIZ - receiver for PLESK"
Date: 19-11-2013
Notes: [
#1 http://stackoverflow.com/questions/14123618/how-to-write-a-hello-world-cgi-with-rebol-3
]
]
; ADD CUSTOM ERRORS TO SYSTEM CATALOG
foreach [id code][
unknown-user ["Unknown user:" :arg1]
wrong-password ["Wrong password"]
user-exists ["User" :arg1 "already exists"]
][
append system/catalog/errors/access reduce [id code]
]
make-liz-error: func [
err-type
err-id
args
][
make error! [
type: err-type
id: err-id
arg1: args/1
arg2: args/2
arg3: args/3
]
]
; ==============
serve-page: func [
"Serve HTML page (add propper header)"
page
][
print "Content-type: text/html^/"
print page
]
dehex: funct [
"Converts URL-style hex encoded (%xx) strings. Process Unicode characters properly."
value [ any-string! ] "The string to dehex"
][
parse value: to binary! value [
some [
change #"+" #" "
| [
m: #"%"
( change/part m load rejoin [ "#{" to string! copy/part next m 2 "}" ] 3 )
]
| skip
]
]
to string! value
]
read-string: func [
"Return file content as string! or return empty string! when file not found"
filename
][
either exists? filename [
to string! read file
][
copy ""
]
]
handle-post: funct [] [
data: none
data: to string! read system/ports/input
if data [ data: parse data "&=" ]
data
]
solve-recaptcha: func [
recaptcha [object!]
/local reply
][
reply: to string! write http://www.google.com/recaptcha/api/verify to-www-form recaptcha
reply: parse reply "^/"
either equal? "true" reply/1 [
true
][
; should return as error?
reply/2
]
]
make-password: funct [
{Make random password. Unless WITH is specified, MAKE-PASSWORD uses ^/
all charsets, but doesn't check if they're present in generated password.}
length "Password length in characters"
/with "Required charsets: uppercase, lowercase, numbers, symbols, all"
required [word! block!]
; TODO: exclude similar chars (i, I, 1, l, o, O, 0, etc.)
][
uppercase: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
lowercase: "abcdefghijklmnopqrstuvwxyz"
numbers: "0123456789"
symbols: "!@#$%^^&*()+-=-/|\()[]{}'§"
; normalize REQUIRED block!
unless block? required [ required: append copy [] required ]
if any [
not with
find required 'all
][
required: [ uppercase lowercase numbers symbols ]
]
; check for errors
unless parse required [
some [ 'uppercase | 'lowercase | 'numbers | 'symbols ]
][
return make error! "Invalid charset in WITH block. Allowed charsets are: uppercase, lowercase, numbers, symbols, all."
]
if all [
with
length < length? required
][
return make error! rejoin [ "Password is too short, at least " length? required " characters are expected." ]
]
; set some variables
out: make string! length
chars: make string! 100
used: array/initial length? required false
; this does what it says
this: func [what][get bind what 'out]
; create pool of chars to choose from
foreach set required [
append chars this set
]
; get some entropy
random/seed now/time/precise
; create password and check if all required chars were used
loop length [
char: random/secure/only chars
append out char
repeat i length? required [
if find this required/:i char [
used/:i: true
]
]
]
; if something's missing, create new password
if all [
with
not all used
][
out: make-password/with length required
]
; return result
out
]
make-salt: func [
"Return unique string (date, time and random value)"
][
rejoin [ now/date ", " now/time/precise ", " random/secure 4294967296 ]
]
make-salted-hash: func [
"Salt data and return SHA1 hash"
data
salt
][
data: checksum/method join salt data 'sha1
]
comment {
Storing password:
* make salt
* cloak salt with salt masterkey
* store cloaked salt in user/<username>/salt
* get checksum of plain salt + plain password
* store checksum in user/<username>/pass
Checking password:
* get cloaked salt from user/<username>/salt
* decloak salt with master massword
* get checksum of plain salt + plain password
* compare checksum with user/<username>/pass
}
; -------- DB
make-key: func [
data
][
make path! reduce data
]
; TODO NOTE: add to redis = send-redis port data : [ parse-reply write port data ]
store-password: funct [
port "Redis database"
username
password
][
salt: make-salt
cloaked-salt: encloak salt salt-key
id: parse-reply write port [ GET ( make-key [ 'user username 'id ] ) ]
write port [ SET ( make-key [ 'user id 'salt ] cloaked-salt ) ]
hash: checksum/method join salt password 'mda1
write port [ SET ( make-key [ 'user id 'password ] hash ) ]
]
check-password: funct [
port
username
password
][
id: parse-reply write port [ GET ( make-key [ 'user username 'id ] ) ]
salt: parse-reply write port [ GET ( make-key [ 'user id 'salt ] ) ]
stored-hash: parse-reply write port [ GET ( make-key [ 'user id 'password ] ) ]
salt: decloak salt salt-key
hash: checksum/method join salt password 'mda1
equal? hash stored-hash
]
store-new-user: func [
port
username
password
][
id: parse-reply write port [ GET last-userid ]
comment {
USER uses following values
user/<username>/id
user/<userid>/username
user/<userid>/password
user/<userid>/salt
}
write port [ SET ( make-key [ 'user username 'id ] ) id ]
write port [ SET ( make-key [ 'user id 'username ] ) username ]
write port [ SET ( make-key [ 'user id 'salt ] ) username ]
write port [ INCR last-userid ]
]
store-salt: func [
"Store encloaked salt"
user
salt
password
][
]