-
-
Notifications
You must be signed in to change notification settings - Fork 10
/
auth.ts
113 lines (101 loc) · 3.03 KB
/
auth.ts
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
/**
* Xpra Typescript Client
* @link https://github.com/andersevenrud/xpra-html5-client
* @author Anders Evenrud <andersevenrud@gmail.com>
* @license Mozilla Public License Version 2.0
*
* ---
*
* Based on original Xpra source
* @copyright Copyright (C) 2016-2022 Antoine Martin <antoine@devloop.org.uk>
* @license Licensed under MPL 2.0, see: http://www.mozilla.org/MPL/2.0/
* @link https://github.com/Xpra-org/xpra-html5
*/
import forge from 'node-forge'
import { xorString, createRandomSecureString } from '../utils/data'
import { XpraChallengeError } from '../errors'
import { XpraChallengeCallback, XpraChallengePrompt } from '../types'
/**
* Creates a digest from a challenge
*/
export function createXpraChallengeDigest(
digest: string,
password: string,
salt: string
) {
if (digest.startsWith('hmac')) {
let hash = 'md5'
if (digest.indexOf('+') > 0) {
hash = digest.split('+')[1]
}
const hmac = forge.hmac.create()
hmac.start(hash as forge.hmac.Algorithm, password)
hmac.update(salt)
return hmac.digest().toHex()
} else if (digest === 'xor') {
const trimmed_salt = salt.slice(0, password.length)
return xorString(trimmed_salt, password)
}
return null
}
/**
* Processes a connection challenge and creates data
* for an appropriate response
*/
export function createXpraChallengeResponse(
serverSalt: string,
digest: string,
saltDigest: string,
password: string,
useSsl: boolean,
useEncryption: string | null
) {
if (!password) {
throw new XpraChallengeError('Invalid login')
}
if (saltDigest === 'xor') {
if (digest === 'xor') {
if (!useSsl && !useEncryption) {
throw new XpraChallengeError(
'Aborted challenge because xor is not safe in this environment'
)
}
}
if (serverSalt.length < 16 || serverSalt.length > 256) {
throw new XpraChallengeError(
`Invalid challenge xor salt length: ${serverSalt.length}`
)
}
}
const clientSaltLength = saltDigest === 'xor' ? serverSalt.length : 32
const clientSalt = createRandomSecureString(clientSaltLength)
const salt = createXpraChallengeDigest(saltDigest, clientSalt, serverSalt)
let challengeResponse = null
if (salt) {
challengeResponse = createXpraChallengeDigest(digest, password, salt)
}
if (!challengeResponse) {
throw new XpraChallengeError('Could not challenge server auth attempt')
}
return [challengeResponse, clientSalt]
}
/**
* Processes and handles a keycloak challenge attempt
*/
export function handleXpraKeycloakChallenge(
challenge: XpraChallengePrompt,
cb: XpraChallengeCallback
) {
const params = new URLSearchParams(window.location.search)
const code = params.get('code')
const error = params.get('error')
const error_description = params.get('error_description')
if (error) {
cb(JSON.stringify({ error, error_description }))
} else if (!code) {
window.location.href = challenge.serverSalt
} else {
history.replaceState({}, '', window.location.pathname)
cb(JSON.stringify({ code }))
}
}