feat(dev): add u2f ui for managing devices and signing in (#2182)

* feat: add u2f ui for managing devices and signing in

* refactor: change unnecessary useState to derived constant

* fix: modal refactor

* fix(web): hide u2f under feature trunk

* fix(web): jest setup

---------

Co-authored-by: Aman Harwara <amanharwara@protonmail.com>
This commit is contained in:
Karol Sójko
2023-02-03 07:54:56 +01:00
committed by GitHub
parent b4f14c668d
commit 9414774e89
48 changed files with 552 additions and 190 deletions

View File

@@ -4,5 +4,4 @@ export enum AuthenticatorApiOperations {
GenerateRegistrationOptions,
GenerateAuthenticationOptions,
VerifyRegistrationResponse,
VerifyAuthenticationResponse,
}

View File

@@ -9,7 +9,6 @@ import {
GenerateAuthenticatorRegistrationOptionsResponse,
VerifyAuthenticatorRegistrationResponseResponse,
GenerateAuthenticatorAuthenticationOptionsResponse,
VerifyAuthenticatorAuthenticationResponseResponse,
} from '../../Response'
import { AuthenticatorServerInterface } from '../../Server/Authenticator/AuthenticatorServerInterface'
@@ -79,7 +78,7 @@ export class AuthenticatorApiService implements AuthenticatorApiServiceInterface
async verifyRegistrationResponse(
userUuid: string,
name: string,
registrationCredential: Record<string, unknown>,
attestationResponse: Record<string, unknown>,
): Promise<VerifyAuthenticatorRegistrationResponseResponse> {
if (this.operationsInProgress.get(AuthenticatorApiOperations.VerifyRegistrationResponse)) {
throw new ApiCallError(ErrorMessage.GenericInProgress)
@@ -91,7 +90,7 @@ export class AuthenticatorApiService implements AuthenticatorApiServiceInterface
const response = await this.authenticatorServer.verifyRegistrationResponse({
userUuid,
name,
registrationCredential,
attestationResponse,
})
return response
@@ -102,7 +101,7 @@ export class AuthenticatorApiService implements AuthenticatorApiServiceInterface
}
}
async generateAuthenticationOptions(): Promise<GenerateAuthenticatorAuthenticationOptionsResponse> {
async generateAuthenticationOptions(username: string): Promise<GenerateAuthenticatorAuthenticationOptionsResponse> {
if (this.operationsInProgress.get(AuthenticatorApiOperations.GenerateAuthenticationOptions)) {
throw new ApiCallError(ErrorMessage.GenericInProgress)
}
@@ -110,7 +109,9 @@ export class AuthenticatorApiService implements AuthenticatorApiServiceInterface
this.operationsInProgress.set(AuthenticatorApiOperations.GenerateAuthenticationOptions, true)
try {
const response = await this.authenticatorServer.generateAuthenticationOptions()
const response = await this.authenticatorServer.generateAuthenticationOptions({
username,
})
return response
} catch (error) {
@@ -119,28 +120,4 @@ export class AuthenticatorApiService implements AuthenticatorApiServiceInterface
this.operationsInProgress.set(AuthenticatorApiOperations.GenerateAuthenticationOptions, false)
}
}
async verifyAuthenticationResponse(
userUuid: string,
authenticationCredential: Record<string, unknown>,
): Promise<VerifyAuthenticatorAuthenticationResponseResponse> {
if (this.operationsInProgress.get(AuthenticatorApiOperations.VerifyAuthenticationResponse)) {
throw new ApiCallError(ErrorMessage.GenericInProgress)
}
this.operationsInProgress.set(AuthenticatorApiOperations.VerifyAuthenticationResponse, true)
try {
const response = await this.authenticatorServer.verifyAuthenticationResponse({
authenticationCredential,
userUuid,
})
return response
} catch (error) {
throw new ApiCallError(ErrorMessage.GenericFail)
} finally {
this.operationsInProgress.set(AuthenticatorApiOperations.VerifyAuthenticationResponse, false)
}
}
}

View File

@@ -4,7 +4,6 @@ import {
GenerateAuthenticatorRegistrationOptionsResponse,
VerifyAuthenticatorRegistrationResponseResponse,
GenerateAuthenticatorAuthenticationOptionsResponse,
VerifyAuthenticatorAuthenticationResponseResponse,
} from '../../Response'
export interface AuthenticatorApiServiceInterface {
@@ -14,11 +13,7 @@ export interface AuthenticatorApiServiceInterface {
verifyRegistrationResponse(
userUuid: string,
name: string,
registrationCredential: Record<string, unknown>,
attestationResponse: Record<string, unknown>,
): Promise<VerifyAuthenticatorRegistrationResponseResponse>
generateAuthenticationOptions(): Promise<GenerateAuthenticatorAuthenticationOptionsResponse>
verifyAuthenticationResponse(
userUuid: string,
authenticationCredential: Record<string, unknown>,
): Promise<VerifyAuthenticatorAuthenticationResponseResponse>
generateAuthenticationOptions(username: string): Promise<GenerateAuthenticatorAuthenticationOptionsResponse>
}

View File

@@ -0,0 +1,3 @@
export interface GenerateAuthenticatorAuthenticationOptionsRequestParams {
username: string
}

View File

@@ -1,5 +0,0 @@
export interface VerifyAuthenticatorAuthenticationResponseRequestParams {
userUuid: string
authenticationCredential: Record<string, unknown>
[additionalParam: string]: unknown
}

View File

@@ -1,6 +1,6 @@
export interface VerifyAuthenticatorRegistrationResponseRequestParams {
userUuid: string
name: string
registrationCredential: Record<string, unknown>
attestationResponse: Record<string, unknown>
[additionalParam: string]: unknown
}

View File

@@ -1,7 +1,7 @@
export * from './ApiEndpointParam'
export * from './Authenticator/DeleteAuthenticatorRequestParams'
export * from './Authenticator/GenerateAuthenticatorAuthenticationOptionsRequestParams'
export * from './Authenticator/ListAuthenticatorsRequestParams'
export * from './Authenticator/VerifyAuthenticatorAuthenticationResponseRequestParams'
export * from './Authenticator/VerifyAuthenticatorRegistrationResponseRequestParams'
export * from './Recovery/RecoveryKeyParamsRequestParams'
export * from './Recovery/SignInWithRecoveryCodesRequestParams'

View File

@@ -1,10 +0,0 @@
import { Either } from '@standardnotes/common'
import { HttpErrorResponseBody } from '../../Http/HttpErrorResponseBody'
import { HttpResponse } from '../../Http/HttpResponse'
import { VerifyAuthenticatorAuthenticationResponseResponseBody } from './VerifyAuthenticatorAuthenticationResponseResponseBody'
export interface VerifyAuthenticatorAuthenticationResponseResponse extends HttpResponse {
data: Either<VerifyAuthenticatorAuthenticationResponseResponseBody, HttpErrorResponseBody>
}

View File

@@ -1,3 +0,0 @@
export interface VerifyAuthenticatorAuthenticationResponseResponseBody {
success: boolean
}

View File

@@ -8,8 +8,6 @@ export * from './Authenticator/GenerateAuthenticatorRegistrationOptionsResponse'
export * from './Authenticator/GenerateAuthenticatorRegistrationOptionsResponseBody'
export * from './Authenticator/ListAuthenticatorsResponse'
export * from './Authenticator/ListAuthenticatorsResponseBody'
export * from './Authenticator/VerifyAuthenticatorAuthenticationResponseResponse'
export * from './Authenticator/VerifyAuthenticatorAuthenticationResponseResponseBody'
export * from './Authenticator/VerifyAuthenticatorRegistrationResponseResponse'
export * from './Authenticator/VerifyAuthenticatorRegistrationResponseResponseBody'
export * from './Recovery/GenerateRecoveryCodesResponse'

View File

@@ -1,9 +1,9 @@
import { HttpServiceInterface } from '../../Http/HttpServiceInterface'
import {
ListAuthenticatorsRequestParams,
GenerateAuthenticatorAuthenticationOptionsRequestParams,
DeleteAuthenticatorRequestParams,
VerifyAuthenticatorRegistrationResponseRequestParams,
VerifyAuthenticatorAuthenticationResponseRequestParams,
} from '../../Request'
import {
ListAuthenticatorsResponse,
@@ -11,7 +11,6 @@ import {
GenerateAuthenticatorRegistrationOptionsResponse,
VerifyAuthenticatorRegistrationResponseResponse,
GenerateAuthenticatorAuthenticationOptionsResponse,
VerifyAuthenticatorAuthenticationResponseResponse,
} from '../../Response'
import { AuthenticatorServerInterface } from './AuthenticatorServerInterface'
import { Paths } from './Paths'
@@ -45,17 +44,11 @@ export class AuthenticatorServer implements AuthenticatorServerInterface {
return response as VerifyAuthenticatorRegistrationResponseResponse
}
async generateAuthenticationOptions(): Promise<GenerateAuthenticatorAuthenticationOptionsResponse> {
const response = await this.httpService.get(Paths.v1.generateAuthenticationOptions)
async generateAuthenticationOptions(
params: GenerateAuthenticatorAuthenticationOptionsRequestParams,
): Promise<GenerateAuthenticatorAuthenticationOptionsResponse> {
const response = await this.httpService.post(Paths.v1.generateAuthenticationOptions, params)
return response as GenerateAuthenticatorAuthenticationOptionsResponse
}
async verifyAuthenticationResponse(
params: VerifyAuthenticatorAuthenticationResponseRequestParams,
): Promise<VerifyAuthenticatorAuthenticationResponseResponse> {
const response = await this.httpService.post(Paths.v1.verifyAuthenticationResponse, params)
return response as VerifyAuthenticatorAuthenticationResponseResponse
}
}

View File

@@ -2,7 +2,7 @@ import {
ListAuthenticatorsRequestParams,
DeleteAuthenticatorRequestParams,
VerifyAuthenticatorRegistrationResponseRequestParams,
VerifyAuthenticatorAuthenticationResponseRequestParams,
GenerateAuthenticatorAuthenticationOptionsRequestParams,
} from '../../Request'
import {
ListAuthenticatorsResponse,
@@ -10,7 +10,6 @@ import {
GenerateAuthenticatorRegistrationOptionsResponse,
VerifyAuthenticatorRegistrationResponseResponse,
GenerateAuthenticatorAuthenticationOptionsResponse,
VerifyAuthenticatorAuthenticationResponseResponse,
} from '../../Response'
export interface AuthenticatorServerInterface {
@@ -20,8 +19,7 @@ export interface AuthenticatorServerInterface {
verifyRegistrationResponse(
params: VerifyAuthenticatorRegistrationResponseRequestParams,
): Promise<VerifyAuthenticatorRegistrationResponseResponse>
generateAuthenticationOptions(): Promise<GenerateAuthenticatorAuthenticationOptionsResponse>
verifyAuthenticationResponse(
params: VerifyAuthenticatorAuthenticationResponseRequestParams,
): Promise<VerifyAuthenticatorAuthenticationResponseResponse>
generateAuthenticationOptions(
params: GenerateAuthenticatorAuthenticationOptionsRequestParams,
): Promise<GenerateAuthenticatorAuthenticationOptionsResponse>
}

View File

@@ -4,7 +4,6 @@ const AuthenticatorPaths = {
generateRegistrationOptions: '/v1/authenticators/generate-registration-options',
verifyRegistrationResponse: '/v1/authenticators/verify-registration',
generateAuthenticationOptions: '/v1/authenticators/generate-authentication-options',
verifyAuthenticationResponse: '/v1/authenticators/verify-authentication',
}
export const Paths = {