-
Notifications
You must be signed in to change notification settings - Fork 32
Expand file tree
/
Copy pathindex.js
More file actions
119 lines (115 loc) · 3.32 KB
/
Copy pathindex.js
File metadata and controls
119 lines (115 loc) · 3.32 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
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
114
115
116
117
118
119
const express = require('express');
const path = require('path');
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
require('dotenv').config();
const SimpleWebAuthnServer = require('@simplewebauthn/server');
const base64url = require('base64url');
app.use(cors({ origin: '*' }));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
let users = {};
let challenges = {};
const rpId = 'localhost';
const expectedOrigin = ['http://localhost:3000'];
app.listen(process.env.PORT || 3000, err => {
if (err) throw err;
console.log('Server started on port', process.env.PORT || 3000);
});
app.use(express.static(path.join(__dirname, 'passkey-frontend/dist/passkey-frontend/browser')));
app.post('/register/start', (req, res) => {
let username = req.body.username;
let challenge = getNewChallenge();
challenges[username] = convertChallenge(challenge);
const pubKey = {
challenge: challenge,
rp: {id: rpId, name: 'webauthn-app'},
user: {id: username, name: username, displayName: username},
pubKeyCredParams: [
{type: 'public-key', alg: -7},
{type: 'public-key', alg: -257},
],
authenticatorSelection: {
authenticatorAttachment: 'platform',
userVerification: 'required',
residentKey: 'preferred',
requireResidentKey: false,
}
};
res.json(pubKey);
});
app.post('/register/finish', async (req, res) => {
const username = req.body.username;
// Verify the attestation response
let verification;
try {
verification = await SimpleWebAuthnServer.verifyRegistrationResponse({
response: req.body.data,
expectedChallenge: challenges[username],
expectedOrigin:expectedOrigin
});
} catch (error) {
console.error(error);
return res.status(400).send({error: error.message});
}
const {verified, registrationInfo} = verification;
if (verified) {
users[username] = registrationInfo;
return res.status(200).send({
res: verified
});
}
res.status(500).send({
res: verified
});
});
app.post('/login/start', (req, res) => {
let username = req.body.username;
if (!users[username]) {
return res.status(404).send(false);
}
let challenge = getNewChallenge();
challenges[username] = convertChallenge(challenge);
res.json({
challenge,
rpId,
allowCredentials: [{
type: 'public-key',
id: users[username].credentialID,
transports: ['internal'],
}],
userVerification: 'preferred',
});
});
app.post('/login/finish', async (req, res) => {
let username = req.body.username;
if (!users[username]) {
return res.status(404).send(false);
}
let verification;
try {
const user = users[username];
verification = await SimpleWebAuthnServer.verifyAuthenticationResponse({
expectedChallenge: challenges[username],
response: req.body.data,
authenticator: user,
expectedRPID: rpId,
expectedOrigin,
requireUserVerification: false
});
} catch (error) {
console.error(error);
return res.status(400).send({error: error.message});
}
const {verified} = verification;
return res.status(200).send({
res: verified
});
});
function getNewChallenge() {
return Math.random().toString(36).substring(2);
}
function convertChallenge(challenge) {
return btoa(challenge).replaceAll('=', '');
}