-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.nim
144 lines (116 loc) · 4.1 KB
/
main.nim
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
import jester, asyncdispatch, re, strutils, random, times
import ./inc/config, ./inc/util, ./inc/html
# emulate virtual host, lol
template thisHost (truth : bool = true): bool =
(request.host == config.gatewayHost) == truth
# redirect client to error landing
proc errorRedirect (err: string): string = (errorPageLocation & %%err)
proc revisited(req: Request): bool =
try:
cryptoHash(req.cookies["id"]) == req.cookies["sign"]
except:
false
import httpclient
proc remoteLog(a: string): bool =
try:
let res = request(url=logURL % (%%a), timeout=defaultTimeout).body
if res.contains("ok"):
true
else:
false
except:
false
proc redirectedFrom(request: Request): string =
# https redirects do not work %) so assumming http
"http://$1:$2$3" % [request.host, $request.port, request.path]
var methods = initTable[string, Method]()
when SMS_ENABLED:
import ./inc/sms
methods["sms"] = SMS_METHOD
proc errorSMSRedirect (phone, err: string): string =
"http://$1/sms_code?phone=$2&error=$3" % [gatewayHost, phone, %%err]
when FB_ENABLED:
import ./inc/fb
methods["fb"] = FB_METHOD
when VK_ENABLED:
import ./inc/vk
methods["vk"] = VK_METHOD
when OK_ENABLED:
import ./inc/ok
methods["ok"] = OK_METHOD
routes:
get "/":
headers["Connection"] = "close"
if request.params.hasKey("from"):
setCookie("from", @"from", daysForward(1))
cond thisHost
resp html.mainPage(pageCtx(
error: @"error",
revisited: revisited request,
))
# redirect rule (any transparent-proxied URL will be redirected to our host
get re".*":
headers["Connection"] = "close"
cond thisHost false
headers["Cache-Control"] = "no-store"
headers["Connection"] = "close"
redirect "http://$1/" % config.gatewayHost
# oauth step1 (redirect to outside login page)
get re"^\/(.*)_redirect$":
headers["Connection"] = "close"
cond thisHost
let auth = methods[request.matches[0]]
# well; first check is not really needed -- it generates exception
cond auth != nil and auth.Enabled
cond auth.Primary or revisited request
let res = auth.Redirect(request.params)
if res.error != nil:
redirect errorRedirect res.error
else:
# redirecting! do the stuff and redirect
if auth.Hosts != nil:
let cmdResult = allowIP(who=request.ip, what=auth.Hosts)
if cmdResult != 0:
redirect errorRedirect "Could not allow social networks IP"
redirect res.url
# oauth step2 (redirected from outside login page; must check supplied code)
get re"^\/(.*)_callback$":
headers["Connection"] = "close"
cond thisHost
let auth = methods[request.matches[0]]
cond auth != nil and auth.Enabled
cond auth.Primary or revisited request
let res = auth.CheckCode(request.params)
if res.error != nil:
# sms need another page
when SMS_ENABLED:
if request.matches[0] == "sms":
redirect errorSMSRedirect(@"phone", res.error)
redirect errorRedirect res.error
else:
if auth.Primary: # save identity
setCookie("id", res.id, daysForward(365 * 5))
setCookie("sign", cryptoHash(res.id), daysForward(365 * 5))
if not remoteLog("Id: $1;\tIp addr: $2" % [res.id, request.ip]):
redirect errorRedirect "Could not log"
else:
if not remoteLog("Id: $1;\tSecondary Id: $2;\tIp addr: $3" % [request.cookies["id"], res.id, request.ip]):
redirect errorRedirect "Could not log"
# success! allow internet access and all the stuff
let cmdResult = allowInternetAccess request.ip
if cmdResult != 0:
redirect errorRedirect "Could not allow access"
redirect website
# we are self SMS-oauth provider -- serve code enter page
get "/sms_code":
headers["Connection"] = "close"
when SMS_ENABLED: # save binary size if it's disabled
cond smsEnabled
resp html.smsCode(@"phone", @"error")
get "/good":
headers["Connection"] = "close"
resp html.allOk()
randomize() # make sure codes are always different
when not defined(release):
discard remoteLog("Starting service")
runForever()