| 186 | } |
| 187 | |
| 188 | async post({ domainId, result, redirect }) { |
| 189 | const challenge = this.session.challenge; |
| 190 | if (!challenge) throw new ForbiddenError('no-challenge'); |
| 191 | const tdoc = await token.get(challenge, token.TYPE_WEBAUTHN); |
| 192 | if (!tdoc) throw new InvalidTokenError(token.TYPE_TEXTS[token.TYPE_WEBAUTHN]); |
| 193 | const udoc = await (tdoc.uid === 'login' |
| 194 | ? (async () => { |
| 195 | const u = await user.coll.findOne({ 'authenticators.credentialID': Binary.createFromBase64(result.id) }); |
| 196 | return u ? await user.getById(domainId, u._id) : null; |
| 197 | })() |
| 198 | : user.getById(domainId, tdoc.uid)); |
| 199 | if (!udoc) throw new NotFoundError(); |
| 200 | const parseId = (id: Binary) => Buffer.from(id.toString('hex'), 'hex').toString('base64url'); |
| 201 | const authenticator = udoc._authenticators?.find((c) => parseId(c.credentialID) === result.id); |
| 202 | if (!authenticator) throw new ValidationError('authenticator'); |
| 203 | const verification = await verifyAuthenticationResponse({ |
| 204 | response: result, |
| 205 | expectedChallenge: challenge, |
| 206 | expectedOrigin: this.request.headers.origin, |
| 207 | expectedRPID: this.getAuthnHost(), |
| 208 | credential: { |
| 209 | ...authenticator, |
| 210 | id: isoBase64URL.fromBuffer(new Uint8Array(authenticator.credentialID.buffer)), |
| 211 | publicKey: new Uint8Array(authenticator.credentialPublicKey.buffer), |
| 212 | }, |
| 213 | }).catch(() => null); |
| 214 | if (!verification?.verified) throw new ValidationError('authenticator'); |
| 215 | authenticator.counter = verification.authenticationInfo.newCounter; |
| 216 | await user.setById(udoc._id, { authenticators: udoc._authenticators }); |
| 217 | if (tdoc.uid === 'login') { |
| 218 | await successfulAuth.call(this, await user.getById(domainId, udoc._id)); |
| 219 | await token.del(challenge, token.TYPE_WEBAUTHN); |
| 220 | this.response.redirect = redirect || ((this.request.referer || '/login').endsWith('/login') |
| 221 | ? this.url('homepage') : this.request.referer); |
| 222 | } else { |
| 223 | await token.update(challenge, token.TYPE_WEBAUTHN, 60, { verified: true }); |
| 224 | this.back(); |
| 225 | } |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | class UserLogoutHandler extends Handler { |