parsav  Diff

Differences From Artifact [434636bebc]:

To Artifact [da67d9c6fd]:


     4      4   login_form(co: &lib.srv.convo, user: &lib.store.actor, creds: &lib.store.credset, msg: pstr)
     5      5   	var doc = [lib.srv.convo.page] {
     6      6   		title = 'instance logon';
     7      7   		class = 'login';
     8      8   		cache = false;
     9      9   	}
    10     10   
           11  +	var how = co:ppostv('how')
           12  +
    11     13   	if user == nil then
    12     14   		var form = data.view.login_username {
    13     15   			loginmsg = msg;
    14     16   		}
    15     17   		if form.loginmsg.ptr == nil then
    16     18   			form.loginmsg = 'identify yourself for access to this instance.'
    17     19   		end
    18     20   		doc.body = form:tostr()
    19     21   	elseif creds:sz() == 0 then
    20     22   		co:complain(403,'access denied','your host is not eligible to authenticate as this user')
    21     23   		return
    22         -	elseif creds:sz() == 1 then
           24  +	elseif creds:sz() == 1 or how:ref() then
           25  +		var newcreds: lib.store.credset
           26  +		if how:ref() then
           27  +			if     how:cmp('pw')    then newcreds = creds and [lib.store.credset.bits.pw]
           28  +			elseif how:cmp('chlg')  then newcreds = creds and [lib.store.credset.bits.challenge]
           29  +			elseif how:cmp('otp')   then newcreds = creds and [lib.store.credset.bits.otp]
           30  +			elseif how:cmp('trust') then newcreds = creds and [lib.store.credset.bits.trust]
           31  +			else co:complain(400, 'bad request', 'the requested authentication method is not available') return end
           32  +			creds = &newcreds
           33  +		end
           34  +
    23     35   		if creds.trust() then
    24     36   			-- TODO log in immediately
    25     37   			return
    26     38   		end
    27     39   
    28     40   		var ch = data.view.login_challenge {
    29     41   			handle = user.handle;
    30     42   			name = lib.coalesce(user.nym, user.handle);
    31     43   		}
    32     44   		if creds.pw() then
    33     45   			ch.challenge = 'enter the password associated with your account'
    34     46   			ch.label = 'password'
    35     47   			ch.method = 'pw'
    36         -			ch.auto = 'current-password';
           48  +			ch.inputfield = '<input type="password" autocomplete="current-password" name="response" id="response" autofocus required>';
    37     49   		elseif creds.otp() then
    38     50   			ch.challenge = 'enter a valid one-time password for your account'
    39     51   			ch.label = 'OTP code'
    40     52   			ch.method = 'otp'
    41         -			ch.auto = 'one-time-code';
           53  +			ch.inputfield = '<input type="text" autocomplete="one-time-code" name="response" id="response" autofocus required>';
    42     54   		elseif creds.challenge() then
    43         -			ch.challenge = 'sign the challenge token: <code>...</code>'
           55  +			var tok   = co:stra(128)
           56  +			var chlg  = co:stra(128)
           57  +			var input = co:stra(256)
           58  +			var time = lib.osclock.time(nil)
           59  +
           60  +			lib.crypt.cryptogram(&tok,6)
           61  +			chlg:lpush 'sign the challenge token <code style="display:block;user-select: all">'
           62  +			    :push(tok.buf,tok.sz)
           63  +				:lpush '</code>'
           64  +
           65  +			ch.challenge = chlg:finalize()
    44     66   			ch.label = 'digest'
    45     67   			ch.method = 'challenge'
    46         -			ch.auto = 'one-time-code';
           68  +			input:lpush '<textarea autocomplete="one-time-code" name="response" id="response" autofocus required></textarea><input type="hidden" name="time" value="'
           69  +			     :shpush(time)
           70  +				 :lpush '"><input type="hidden" name="token" value="'
           71  +			     :push(tok.buf,tok.sz)
           72  +			tok:shpush(time)
           73  +			var hmac = lib.crypt.hmacp(&co.srv.pool,
           74  +							lib.crypt.alg.sha256,
           75  +							co.srv.cfg.secret:blob(),
           76  +							tok:finalize())
           77  +			input:lpush '"><input type="hidden" name="vfy" value="'
           78  +				 :shpush(lib.math.truncate64(hmac.ptr, hmac.ct)) -- FIXME this is probably not very secure...
           79  +				 :lpush '">'
           80  +				 
           81  +			ch.inputfield = input:finalize()
    47     82   		else
    48         -			co:complain(500,'login failure','unknown login method')
           83  +			co:complain(400,'login failure','no usable login methods are available')
    49     84   			return
    50     85   		end
    51     86   
    52         -		doc.body = ch:tostr()
    53         -	else
    54         -		-- pick a method
           87  +		doc.body = ch:poolstr(&co.srv.pool)
           88  +	else -- pick a method
           89  +		var a = co:stra(400)
           90  +		var username = lib.html.sanitize(&co.srv.pool, pstr{user.handle,0}, true)
           91  +		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'">'
           92  +		if creds.trust()     then a:lpush '<button name="how" value="trust">trust</button>'    end
           93  +		if creds.pw()        then a:lpush '<button name="how" value="pw">password</button>'    end
           94  +		if creds.otp()       then a:lpush '<button name="how" value="otp">TOTP code</button>'  end
           95  +		if creds.challenge() then a:lpush '<button name="how" value="chlg">challenge</button>' end
           96  +		a:lpush '</menu></form>'
           97  +		doc.body = a:finalize()
    55     98   	end
    56     99   
    57    100   	co:stdpage(doc)
    58         -	doc.body:free()
          101  +	--doc.body:free()
    59    102   end
    60    103   
    61    104   return login_form