-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathWebAuthn.ts
More file actions
85 lines (75 loc) · 2.63 KB
/
WebAuthn.ts
File metadata and controls
85 lines (75 loc) · 2.63 KB
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
import { server } from '@passwordless-id/webauthn';
import { CollectedClientData } from '@passwordless-id/webauthn/dist/esm/types';
import { BadRequestError, Body, HttpCode, JsonController, Post } from 'routing-controllers';
import { ResponseSchema } from 'routing-controllers-openapi';
import {
dataSource,
User,
UserCredential,
WebAuthnAuthentication,
WebAuthnChallenge,
WebAuthnRegistration
} from '../model';
import { activityLogService, sessionService } from '../service';
const credentialStore = dataSource.getRepository(UserCredential);
@JsonController('/user/WebAuthn')
export class WebAuthnController {
@Post('/challenge')
@HttpCode(201)
@ResponseSchema(WebAuthnChallenge)
createChallenge() {
return { string: server.randomChallenge() };
}
@Post('/registration')
@HttpCode(201)
@ResponseSchema(User)
async signUp(@Body() { challenge, ...registration }: WebAuthnRegistration) {
const { origin } = JSON.parse(
atob(registration.response.clientDataJSON)
) as CollectedClientData;
const {
authenticator,
credential: { id: uuid, ...credential },
synced,
user: { id, name },
userVerified
} = await server.verifyRegistration(registration, {
challenge,
origin
});
const createdBy = await sessionService.signUp({
email: name,
password: id
});
const saved = await credentialStore.save({
createdBy,
uuid,
authenticator,
...credential,
synced,
userVerified
} as UserCredential);
await activityLogService.logCreate(createdBy, 'UserCredential', saved.id);
return sessionService.sign(createdBy);
}
@Post('/authentication')
@HttpCode(201)
@ResponseSchema(User)
async signIn(@Body() { challenge, ...authentication }: WebAuthnAuthentication) {
const userCredential = await credentialStore.findOne({
where: { uuid: authentication.id },
relations: ['createdBy']
});
if (!userCredential) throw new BadRequestError('Invalid credential');
const { uuid, userVerified, createdBy, ...credential } = userCredential,
{ origin } = JSON.parse(
atob(authentication.response.clientDataJSON)
) as CollectedClientData;
await server.verifyAuthentication(
authentication,
{ ...credential, id: uuid },
{ origin, challenge, userVerified }
);
return sessionService.sign(createdBy);
}
}