better code: logic separated from UI
Massimo Melina committed
May 23, 2022 at 19:59 UTC
b1e3f2259602575a2e2c8abcc059e3e5fc99452b
4 files changed
+33
-48
admin/src/LoginRequired.ts
+5
-15
@@ -3,7 +3,7 @@ import { createElement as h, Fragment, useState } from 'react'
3
import { Center } from './misc'
4
import { Form } from './Form'
5
import { apiCall } from './api'
6
-import { SRPClientSession, SRPParameters, SRPRoutines } from 'tssrp6a'
6
+import { srpSequence } from '@hfs/shared'
7
import { Alert } from '@mui/material'
8
9
export function LoginRequired({ children }: any) {
@@ -47,20 +47,10 @@ function LoginForm() {
47
}
48
49
async function login(username: string, password: string) {
50
- const WRONG = "Wrong username or password"
51
- const { pubKey, salt } = await apiCall('loginSrp1', { username })
52
- .catch(() => { throw WRONG })
53
- if (!salt)
54
- throw "Bad response from server"
55
-
56
- const srp6aNimbusRoutines = new SRPRoutines(new SRPParameters())
57
- const srp = new SRPClientSession(srp6aNimbusRoutines);
58
- const resStep1 = await srp.step1(username, password)
59
- const resStep2 = await resStep1.step2(BigInt(salt), BigInt(pubKey))
60
- const res = await apiCall('loginSrp2', { pubKey: String(resStep2.A), proof: String(resStep2.M1) }) // bigint-s must be cast to string to be json-ed
61
- .catch(() => { throw WRONG })
62
- await resStep2.step3(BigInt(res.proof))
63
- .catch(() => { throw "Login aborted: server identity cannot be trusted" })
50
+ const res = await srpSequence(username, password, apiCall).catch(err => {
51
+ throw err === 'trust' ? "Login aborted: server identity cannot be trusted"
52
+ : "Wrong username or password"
53
+ })
54
if (!res.adminUrl)
55
throw "This account has no Admin access"
56
frontend/src/login.ts
+11
-33
@@ -3,47 +3,25 @@
3
import { apiCall, ApiError } from './api'
4
import { state } from './state'
5
import { alertDialog } from './dialog'
6
-import { SRPClientSession, SRPParameters, SRPRoutines } from 'tssrp6a'
7
-import { working } from './misc'
6
+import { srpSequence, working } from './misc'
7
8
export async function login(username:string, password:string) {
9
const stopWorking = working()
11
- try {
12
-/* simple login without encryption. Here commented just for example. Please use SRP version.
13
- const res = await apiCall('login', { username, password })
14
-*/
15
- const { pubKey, salt } = await apiCall('loginSrp1', { username })
16
- if (!salt) return
17
-
18
- const srp6aNimbusRoutines = new SRPRoutines(new SRPParameters())
19
- const srp = new SRPClientSession(srp6aNimbusRoutines);
20
- const resStep1 = await srp.step1(username, password)
21
- const resStep2 = await resStep1.step2(BigInt(salt), BigInt(pubKey))
22
- const res = await apiCall('loginSrp2', { pubKey: String(resStep2.A), proof: String(resStep2.M1) }) // bigint-s must be cast to string to be json-ed
23
- try {
24
- await resStep2.step3(BigInt(res.proof))
25
- }
26
- catch(e){
27
- console.debug(String(e))
28
- stopWorking()
29
- await alertDialog("Login aborted: server identity cannot be trusted", 'error')
30
- return
31
- }
32
-
33
- // login was successful, update state
10
+ return srpSequence(username, password, apiCall).then(res => {
11
+ stopWorking()
12
sessionRefresher(res)
13
return res
36
- }
37
- catch(err) {
14
+ }, (err: Error) => {
15
stopWorking()
39
- if (err instanceof ApiError)
16
+ if (err.message === 'trust')
17
+ err = Error("Login aborted: server identity cannot be trusted")
18
+ else if (err instanceof ApiError)
19
if (err.code === 401)
41
- err = 'Invalid credentials'
20
+ err = Error("Invalid credentials")
21
else if (err.code === 409)
43
- err = 'Cookies not working - login failed'
44
- await alertDialog(err as Error, 'error')
45
- }
46
- finally { stopWorking() }
22
+ err = Error("Cookies not working - login failed")
23
+ return alertDialog(err)
24
+ })
25
}
26
27
// @ts-ignore
shared/package.json
+3
@@ -6,6 +6,9 @@
6
"test": "test",
7
"build": "tsc && yarn sass src/:lib/"
8
},
9
+ "dependencies": {
10
+ "tssrp6a": "^3.0.0"
11
+ },
12
"devDependencies": {
13
"react": "*",
14
"react-dom": "*",
shared/src/index.ts
+14
@@ -1,6 +1,7 @@
1
// This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3
import _ from 'lodash'
4
+import { SRPClientSession, SRPParameters, SRPRoutines } from 'tssrp6a'
5
export * from './react'
6
7
export type Dict<T=any> = Record<string, T>
@@ -66,3 +67,16 @@ export function setHidden(dest: object, src:object) {
67
value,
68
})))
69
}
70
+
71
+export async function srpSequence(username:string, password:string, apiCall: (cmd:string, params:any) => any) {
72
+ const { pubKey, salt } = await apiCall('loginSrp1', { username })
73
+ if (!salt) throw Error('salt')
74
+ const srp6aNimbusRoutines = new SRPRoutines(new SRPParameters())
75
+ const srp = new SRPClientSession(srp6aNimbusRoutines);
76
+ const resStep1 = await srp.step1(username, password)
77
+ const resStep2 = await resStep1.step2(BigInt(salt), BigInt(pubKey))
78
+ const res = await apiCall('loginSrp2', { pubKey: String(resStep2.A), proof: String(resStep2.M1) }) // bigint-s must be cast to string to be json-ed
79
+ await resStep2.step3(BigInt(res.proof)).catch(() => Promise.reject('trust'))
80
+ return res
81
+}
82
+