use consistent terminology: username and account, no "user"

Massimo Melina committed Jan 9, 2022 at 16:53 UTC 58f40e5751da04bd42a42584452b5fb979f428e1
5 files changed +31 -31
frontend/src/login.ts
+8 -8
@@ -6,20 +6,20 @@ import { working } from './misc'
6
7 let refresher: NodeJS.Timeout
8
9 -export async function login(user:string, password:string) {
9 +export async function login(username:string, password:string) {
10 if (refresher)
11 clearInterval(refresher)
12 const stopWorking = working()
13 try {
14 /* simple login without encryption. Here commented just for example. Please use SRP version.
15 - const res = await apiCall('login', { user, password })
15 + const res = await apiCall('login', { username, password })
16 */
17 - const { pubKey, salt } = await apiCall('loginSrp1', { user })
17 + const { pubKey, salt } = await apiCall('loginSrp1', { username })
18 if (!salt) return
19
20 const srp6aNimbusRoutines = new SRPRoutines(new SRPParameters())
21 const srp = new SRPClientSession(srp6aNimbusRoutines);
22 - const resStep1 = await srp.step1(user, password)
22 + const resStep1 = await srp.step1(username, password)
23 const resStep2 = await resStep1.step2(BigInt(salt), BigInt(pubKey))
24 const res = await apiCall('loginSrp2', { pubKey: String(resStep2.A), proof: String(resStep2.M1) }) // bigint-s must be cast to string to be json-ed
25 try {
@@ -32,8 +32,8 @@ export async function login(user:string, password:string) {
32 }
33
34 // login was successful, update state
35 - sessionRefresher({ user, exp:res.exp })
36 - state.username = user
35 + sessionRefresher({ username, exp:res.exp })
36 + state.username = username
37 }
38 catch(err) {
39 if (err instanceof ApiError)
@@ -45,8 +45,8 @@ export async function login(user:string, password:string) {
45 }
46 apiCall('refresh_session').then(sessionRefresher, ()=>{})
47
48 -function sessionRefresher({ exp, user }:{ exp:string, user:string }) {
49 - state.username = user
48 +function sessionRefresher({ exp, username }:{ exp:string, username:string }) {
49 + state.username = username
50 if (!exp) return
51 const delta = new Date(exp).getTime() - Date.now()
52 const every = delta - 30_000
src/api.auth.ts
+12 -12
@@ -13,12 +13,12 @@ function makeExp() {
13 return { exp: new Date(Date.now() + SESSION_DURATION) }
14 }
15
16 -export const login: ApiHandler = async ({ user, password }, ctx) => {
17 - if (!user)
16 +export const login: ApiHandler = async ({ username, password }, ctx) => {
17 + if (!username)
18 return ctx.status = 400
19 if (!password)
20 return ctx.status = 400
21 - const acc = getAccount(user)
21 + const acc = getAccount(username)
22 if (!acc)
23 return ctx.status = 401
24 if (!acc.hashedPassword)
@@ -26,12 +26,12 @@ export const login: ApiHandler = async ({ user, password }, ctx) => {
26 if (!await verifyPassword(acc.hashedPassword, password))
27 return ctx.status = 401
28 if (ctx.session)
29 - ctx.session.user = user
29 + ctx.session.username = username
30 return makeExp()
31 }
32
33 -export const loginSrp1: ApiHandler = async ({ user }, ctx) => {
34 - const account = getAccount(user)
33 +export const loginSrp1: ApiHandler = async ({ username }, ctx) => {
34 + const account = getAccount(username)
35 if (!ctx.session)
36 return ctx.throw(500)
37 if (!account) // TODO simulate fake account to prevent knowing valid usernames
@@ -40,23 +40,23 @@ export const loginSrp1: ApiHandler = async ({ user }, ctx) => {
40 return ctx.status = 406 // unacceptable
41
42 const [salt, verifier] = account.srp.split('|')
43 - const step1 = await srpSession.step1(account.user, BigInt(salt), BigInt(verifier))
43 + const step1 = await srpSession.step1(account.username, BigInt(salt), BigInt(verifier))
44 const sid = Math.random()
45 ongoingLogins[sid] = step1
46 setTimeout(()=> delete ongoingLogins[sid], 60_000)
47
48 - ctx.session.login = { user, sid }
48 + ctx.session.login = { username, sid }
49 return { salt, pubKey: String(step1.B) } // cast to string cause bigint can't be jsonized
50 }
51
52 export const loginSrp2: ApiHandler = async ({ pubKey, proof }, ctx) => {
53 if (!ctx.session)
54 return ctx.throw(500)
55 - const { user, sid } = ctx.session.login
55 + const { username, sid } = ctx.session.login
56 const step1 = ongoingLogins[sid]
57 try {
58 const M2 = await step1.step2(BigInt(pubKey), BigInt(proof))
59 - ctx.session.user = user
59 + ctx.session.username = username
60 return { proof: String(M2), ...makeExp() }
61 }
62 catch(e) {
@@ -67,13 +67,13 @@ export const loginSrp2: ApiHandler = async ({ pubKey, proof }, ctx) => {
67
68 export const logout: ApiHandler = async ({}, ctx) => {
69 if (ctx.session)
70 - ctx.session.user = undefined
70 + ctx.session.username = undefined
71 ctx.status = 200
72 return true
73 }
74
75 export const refresh_session: ApiHandler = async ({}, ctx) => {
76 - return { user: ctx.session?.user, ...makeExp() }
76 + return { username: ctx.session?.username, ...makeExp() }
77 }
78
79 export const change_password: ApiHandler = async ({ newPassword }, ctx) => {
src/perm.ts
+6 -6
@@ -11,7 +11,7 @@ import { createVerifierAndSalt, SRPParameters, SRPRoutines } from 'tssrp6a'
11 let path = ''
12
13 interface Account {
14 - user: string, // we'll have user in it, so we don't need to pass it separately
14 + username: string, // we'll have username in it, so we don't need to pass it separately
15 password?: string
16 hashedPassword?: string
17 srp?: string
@@ -22,7 +22,7 @@ interface Accounts { [username:string]: Account }
22 let accounts: Accounts = {}
23
24 export async function getCurrentUsername(ctx: Koa.Context) {
25 - return ctx.session?.user || ''
25 + return ctx.session?.username || ''
26 }
27
28 // provides the username and all other usernames it inherits based on the 'belongs' attribute. Useful to check permissions
@@ -68,7 +68,7 @@ export async function updateAccount(username: string, changer?:Changer) {
68 }
69 account.belongs = wantArray(account.belongs).filter(b =>
70 b in accounts // at this stage the group record may still be null if specified later in the file
71 - || console.error(`user ${username} belongs to non-existing ${b}`) )
71 + || console.error(`account ${username} belongs to non-existing ${b}`) )
72 if (was !== JSON.stringify(account))
73 saveAccountsAsap()
74 }
@@ -100,10 +100,10 @@ subscribeConfig({ k:'accounts', defaultValue:'accounts.yaml' }, v => {
100 async function applyAccounts(newAccounts:Accounts) {
101 // we should validate content here
102 accounts = newAccounts
103 - await Promise.all(_.map(newAccounts, async (rec,k) => {
103 + await Promise.all(_.map(accounts, async (rec,k) => {
104 if (!rec) // an empty object in yaml is stored as null
105 - rec = accounts[k] = { user: k, srp:'' }
106 - setHidden(rec, { user: k })
105 + rec = accounts[k] = { username: k, srp:'' }
106 + setHidden(rec, { username: k })
107 await updateAccount(k)
108 }))
109 }
tests/test.ts
+3 -3
@@ -8,7 +8,7 @@ const appStarted = new Promise(resolve =>
8 srv.on( 'app_started', resolve) )
9 */
10
11 -const user = 'rejetto'
11 +const username = 'rejetto'
12 const password = 'password'
13
14 describe('basics', () => {
@@ -28,14 +28,14 @@ describe('basics', () => {
28 it('missing perm', req('/for-admins/', 404))
29 it('proxy', req('/proxy', s => s.includes('github')))
30 it('login', req('/~/api/login', 200, {
31 - data: { user, password }
31 + data: { username, password }
32 }))
33 })
34
35 let cookie:any
36 describe('after-login', () => {
37 before(req('/~/api/login', (data, res) => Boolean(cookie = res.headers['set-cookie']), {
38 - data: { user, password }
38 + data: { username, password }
39 }))
40 it('list protected', done => // defer execution of req() to have cookie set
41 req('/~/api/file_list', data => inList(data, 'alfa.txt'), {
todo.md
+2 -2
@@ -7,8 +7,8 @@
7 - search and login dialogs should push to history so that mobile can use back button to close them
8 - node.comment
9 - config: max connections (total/per-ip)
10 -- user.ignoreLimits
11 -- user.redirect
10 +- account.ignoreLimits
11 +- account.redirect
12 - config: bans
13 - config: min disk space
14 - link to parent folder in the list (as an option of the frontend? plugin?)