parsav  Diff

Differences From Artifact [434636bebc]:

To Artifact [da67d9c6fd]:


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
login_form(co: &lib.srv.convo, user: &lib.store.actor, creds: &lib.store.credset, msg: pstr)
	var doc = [lib.srv.convo.page] {
		title = 'instance logon';
		class = 'login';
		cache = false;
	}



	if user == nil then
		var form = data.view.login_username {
			loginmsg = msg;
		}
		if form.loginmsg.ptr == nil then
			form.loginmsg = 'identify yourself for access to this instance.'
		end
		doc.body = form:tostr()
	elseif creds:sz() == 0 then
		co:complain(403,'access denied','your host is not eligible to authenticate as this user')
		return
	elseif creds:sz() == 1 then










		if creds.trust() then
			-- TODO log in immediately
			return
		end

		var ch = data.view.login_challenge {
			handle = user.handle;
			name = lib.coalesce(user.nym, user.handle);
		}
		if creds.pw() then
			ch.challenge = 'enter the password associated with your account'
			ch.label = 'password'
			ch.method = 'pw'
			ch.auto = 'current-password';
		elseif creds.otp() then
			ch.challenge = 'enter a valid one-time password for your account'
			ch.label = 'OTP code'
			ch.method = 'otp'
			ch.auto = 'one-time-code';
		elseif creds.challenge() then






			ch.challenge = 'sign the challenge token: <code>...</code>'




			ch.label = 'digest'
			ch.method = 'challenge'
			ch.auto = 'one-time-code';














		else
			co:complain(500,'login failure','unknown login method')

			return
		end

		doc.body = ch:tostr()
	else
		-- pick a method









	end

	co:stdpage(doc)
	doc.body:free()
end

return login_form







>
>











|
>
>
>
>
>
>
>
>
>
>













|




|

>
>
>
>
>
>
|
>
>
>
>


<
>
>
>
>
>
>
>
>
>
>
>
>
>
>

<
>



|
<
|
>
>
>
>
>
>
>
>
>



|



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
login_form(co: &lib.srv.convo, user: &lib.store.actor, creds: &lib.store.credset, msg: pstr)
	var doc = [lib.srv.convo.page] {
		title = 'instance logon';
		class = 'login';
		cache = false;
	}

	var how = co:ppostv('how')

	if user == nil then
		var form = data.view.login_username {
			loginmsg = msg;
		}
		if form.loginmsg.ptr == nil then
			form.loginmsg = 'identify yourself for access to this instance.'
		end
		doc.body = form:tostr()
	elseif creds:sz() == 0 then
		co:complain(403,'access denied','your host is not eligible to authenticate as this user')
		return
	elseif creds:sz() == 1 or how:ref() then
		var newcreds: lib.store.credset
		if how:ref() then
			if     how:cmp('pw')    then newcreds = creds and [lib.store.credset.bits.pw]
			elseif how:cmp('chlg')  then newcreds = creds and [lib.store.credset.bits.challenge]
			elseif how:cmp('otp')   then newcreds = creds and [lib.store.credset.bits.otp]
			elseif how:cmp('trust') then newcreds = creds and [lib.store.credset.bits.trust]
			else co:complain(400, 'bad request', 'the requested authentication method is not available') return end
			creds = &newcreds
		end

		if creds.trust() then
			-- TODO log in immediately
			return
		end

		var ch = data.view.login_challenge {
			handle = user.handle;
			name = lib.coalesce(user.nym, user.handle);
		}
		if creds.pw() then
			ch.challenge = 'enter the password associated with your account'
			ch.label = 'password'
			ch.method = 'pw'
			ch.inputfield = '<input type="password" autocomplete="current-password" name="response" id="response" autofocus required>';
		elseif creds.otp() then
			ch.challenge = 'enter a valid one-time password for your account'
			ch.label = 'OTP code'
			ch.method = 'otp'
			ch.inputfield = '<input type="text" autocomplete="one-time-code" name="response" id="response" autofocus required>';
		elseif creds.challenge() then
			var tok   = co:stra(128)
			var chlg  = co:stra(128)
			var input = co:stra(256)
			var time = lib.osclock.time(nil)

			lib.crypt.cryptogram(&tok,6)
			chlg:lpush 'sign the challenge token <code style="display:block;user-select: all">'
			    :push(tok.buf,tok.sz)
				:lpush '</code>'

			ch.challenge = chlg:finalize()
			ch.label = 'digest'
			ch.method = 'challenge'

			input:lpush '<textarea autocomplete="one-time-code" name="response" id="response" autofocus required></textarea><input type="hidden" name="time" value="'
			     :shpush(time)
				 :lpush '"><input type="hidden" name="token" value="'
			     :push(tok.buf,tok.sz)
			tok:shpush(time)
			var hmac = lib.crypt.hmacp(&co.srv.pool,
							lib.crypt.alg.sha256,
							co.srv.cfg.secret:blob(),
							tok:finalize())
			input:lpush '"><input type="hidden" name="vfy" value="'
				 :shpush(lib.math.truncate64(hmac.ptr, hmac.ct)) -- FIXME this is probably not very secure...
				 :lpush '">'
				 
			ch.inputfield = input:finalize()
		else

			co:complain(400,'login failure','no usable login methods are available')
			return
		end

		doc.body = ch:poolstr(&co.srv.pool)

	else -- pick a method
		var a = co:stra(400)
		var username = lib.html.sanitize(&co.srv.pool, pstr{user.handle,0}, true)
		a:lpush '<form action="/login" method="post" class="auth-select"><p>multiple authentication mechanisms are available. select one to continue.</p><menu><input type="hidden" name="user" value="':ppush(username):lpush'">'
		if creds.trust()     then a:lpush '<button name="how" value="trust">trust</button>'    end
		if creds.pw()        then a:lpush '<button name="how" value="pw">password</button>'    end
		if creds.otp()       then a:lpush '<button name="how" value="otp">TOTP code</button>'  end
		if creds.challenge() then a:lpush '<button name="how" value="chlg">challenge</button>' end
		a:lpush '</menu></form>'
		doc.body = a:finalize()
	end

	co:stdpage(doc)
	--doc.body:free()
end

return login_form