From 5ea455b98b8fc0bf212428404d1f6b62af1f630a Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 11 Sep 2021 21:23:06 +0200 Subject: [PATCH] Feature/upgrade simplewebauthn dependencies to version 4.1.0 (#365) * Upgrade @simplewebauthn dependencies to version 4.1.0 * @simplewebauthn/browser * @simplewebauthn/server * Update changelog --- CHANGELOG.md | 8 +++ apps/api/src/app/auth/auth.controller.ts | 6 +- apps/api/src/app/auth/web-auth.service.ts | 72 +++++++++---------- .../pages/webauthn/webauthn-page.module.ts | 2 +- .../src/app/services/web-authn.service.ts | 11 +-- package.json | 6 +- yarn.lock | 42 +++++------ 7 files changed, 79 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a59a7cbd9..b44e2a385 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added the annualized performance to the portfolio summary tab on the home page - Added the Ghostfolio Slack channel to the about page +### Changed + +- Upgraded `@simplewebauthn/browser` and `@simplewebauthn/server` from version `3.0.0` to `4.1.0` + +### Fixed + +- Fixed the sign in with fingerprint for some android devices + ## 1.51.0 - 11.09.2021 ### Changed diff --git a/apps/api/src/app/auth/auth.controller.ts b/apps/api/src/app/auth/auth.controller.ts index 8e6ff846d..5244307dd 100644 --- a/apps/api/src/app/auth/auth.controller.ts +++ b/apps/api/src/app/auth/auth.controller.ts @@ -62,10 +62,10 @@ export class AuthController { } } - @Get('webauthn/generate-attestation-options') + @Get('webauthn/generate-registration-options') @UseGuards(AuthGuard('jwt')) - public async generateAttestationOptions() { - return this.webAuthService.generateAttestationOptions(); + public async generateRegistrationOptions() { + return this.webAuthService.generateRegistrationOptions(); } @Post('webauthn/verify-attestation') diff --git a/apps/api/src/app/auth/web-auth.service.ts b/apps/api/src/app/auth/web-auth.service.ts index 3d8c69b9a..8780fabe9 100644 --- a/apps/api/src/app/auth/web-auth.service.ts +++ b/apps/api/src/app/auth/web-auth.service.ts @@ -11,16 +11,16 @@ import { import { REQUEST } from '@nestjs/core'; import { JwtService } from '@nestjs/jwt'; import { - GenerateAssertionOptionsOpts, - GenerateAttestationOptionsOpts, - VerifiedAssertion, - VerifiedAttestation, - VerifyAssertionResponseOpts, - VerifyAttestationResponseOpts, - generateAssertionOptions, - generateAttestationOptions, - verifyAssertionResponse, - verifyAttestationResponse + GenerateAuthenticationOptionsOpts, + GenerateRegistrationOptionsOpts, + VerifiedAuthenticationResponse, + VerifiedRegistrationResponse, + VerifyAuthenticationResponseOpts, + VerifyRegistrationResponseOpts, + generateAuthenticationOptions, + generateRegistrationOptions, + verifyAuthenticationResponse, + verifyRegistrationResponse } from '@simplewebauthn/server'; import { @@ -46,10 +46,10 @@ export class WebAuthService { return this.configurationService.get('ROOT_URL'); } - public async generateAttestationOptions() { + public async generateRegistrationOptions() { const user = this.request.user; - const opts: GenerateAttestationOptionsOpts = { + const opts: GenerateRegistrationOptionsOpts = { rpName: 'Ghostfolio', rpID: this.rpID, userID: user.id, @@ -63,7 +63,7 @@ export class WebAuthService { } }; - const options = generateAttestationOptions(opts); + const options = generateRegistrationOptions(opts); await this.userService.updateUser({ data: { @@ -84,27 +84,27 @@ export class WebAuthService { const user = this.request.user; const expectedChallenge = user.authChallenge; - let verification: VerifiedAttestation; + let verification: VerifiedRegistrationResponse; try { - const opts: VerifyAttestationResponseOpts = { + const opts: VerifyRegistrationResponseOpts = { credential, expectedChallenge, expectedOrigin: this.expectedOrigin, expectedRPID: this.rpID }; - verification = await verifyAttestationResponse(opts); + verification = await verifyRegistrationResponse(opts); } catch (error) { console.error(error); throw new InternalServerErrorException(error.message); } - const { verified, attestationInfo } = verification; + const { registrationInfo, verified } = verification; const devices = await this.deviceService.authDevices({ where: { userId: user.id } }); - if (verified && attestationInfo) { - const { credentialPublicKey, credentialID, counter } = attestationInfo; + if (registrationInfo && verified) { + const { counter, credentialID, credentialPublicKey } = registrationInfo; let existingDevice = devices.find( (device) => device.credentialId === credentialID @@ -115,9 +115,9 @@ export class WebAuthService { * Add the returned device to the user's list of devices */ existingDevice = await this.deviceService.createAuthDevice({ + counter, credentialPublicKey, credentialId: credentialID, - counter, User: { connect: { id: user.id } } }); } @@ -138,20 +138,20 @@ export class WebAuthService { throw new Error('Device not found'); } - const opts: GenerateAssertionOptionsOpts = { - timeout: 60000, + const opts: GenerateAuthenticationOptionsOpts = { allowCredentials: [ { id: device.credentialId, - type: 'public-key', - transports: ['internal'] + transports: ['internal'], + type: 'public-key' } ], - userVerification: 'preferred', - rpID: this.rpID + rpID: this.rpID, + timeout: 60000, + userVerification: 'preferred' }; - const options = generateAssertionOptions(opts); + const options = generateAuthenticationOptions(opts); await this.userService.updateUser({ data: { @@ -177,29 +177,29 @@ export class WebAuthService { const user = await this.userService.user({ id: device.userId }); - let verification: VerifiedAssertion; + let verification: VerifiedAuthenticationResponse; try { - const opts: VerifyAssertionResponseOpts = { + const opts: VerifyAuthenticationResponseOpts = { credential, - expectedChallenge: `${user.authChallenge}`, - expectedOrigin: this.expectedOrigin, - expectedRPID: this.rpID, authenticator: { credentialID: device.credentialId, credentialPublicKey: device.credentialPublicKey, counter: device.counter - } + }, + expectedChallenge: `${user.authChallenge}`, + expectedOrigin: this.expectedOrigin, + expectedRPID: this.rpID }; - verification = verifyAssertionResponse(opts); + verification = verifyAuthenticationResponse(opts); } catch (error) { console.error(error); throw new InternalServerErrorException({ error: error.message }); } - const { verified, assertionInfo } = verification; + const { verified, authenticationInfo } = verification; if (verified) { - device.counter = assertionInfo.newCounter; + device.counter = authenticationInfo.newCounter; await this.deviceService.updateAuthDevice({ data: device, diff --git a/apps/client/src/app/pages/webauthn/webauthn-page.module.ts b/apps/client/src/app/pages/webauthn/webauthn-page.module.ts index 44aed99b7..4209346e3 100644 --- a/apps/client/src/app/pages/webauthn/webauthn-page.module.ts +++ b/apps/client/src/app/pages/webauthn/webauthn-page.module.ts @@ -2,8 +2,8 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { GfLogoModule } from '@ghostfolio/ui/logo'; import { WebauthnPageComponent } from '@ghostfolio/client/pages/webauthn/webauthn-page.component'; +import { GfLogoModule } from '@ghostfolio/ui/logo'; import { WebauthnPageRoutingModule } from './webauthn-page-routing.module'; diff --git a/apps/client/src/app/services/web-authn.service.ts b/apps/client/src/app/services/web-authn.service.ts index 520202960..154efd9d9 100644 --- a/apps/client/src/app/services/web-authn.service.ts +++ b/apps/client/src/app/services/web-authn.service.ts @@ -6,7 +6,10 @@ import { PublicKeyCredentialRequestOptionsJSON } from '@ghostfolio/api/app/auth/interfaces/simplewebauthn'; import { SettingsStorageService } from '@ghostfolio/client/services/settings-storage.service'; -import { startAssertion, startAttestation } from '@simplewebauthn/browser'; +import { + startAuthentication, + startRegistration +} from '@simplewebauthn/browser'; import { of } from 'rxjs'; import { catchError, switchMap, tap } from 'rxjs/operators'; @@ -32,7 +35,7 @@ export class WebAuthnService { public register() { return this.http .get( - `/api/auth/webauthn/generate-attestation-options`, + `/api/auth/webauthn/generate-registration-options`, {} ) .pipe( @@ -41,7 +44,7 @@ export class WebAuthnService { return of(null); }), switchMap((attOps) => { - return startAttestation(attOps); + return startRegistration(attOps); }), switchMap((attResp) => { return this.http.post( @@ -83,7 +86,7 @@ export class WebAuthnService { { deviceId } ) .pipe( - switchMap(startAssertion), + switchMap(startAuthentication), switchMap((assertionResponse) => { return this.http.post<{ authToken: string }>( `/api/auth/webauthn/verify-assertion`, diff --git a/package.json b/package.json index d70381a94..be0d7e724 100644 --- a/package.json +++ b/package.json @@ -68,9 +68,9 @@ "@nestjs/serve-static": "2.1.4", "@nrwl/angular": "12.8.0", "@prisma/client": "2.30.2", - "@simplewebauthn/browser": "3.0.0", - "@simplewebauthn/server": "3.0.0", - "@simplewebauthn/typescript-types": "3.0.0", + "@simplewebauthn/browser": "4.1.0", + "@simplewebauthn/server": "4.1.0", + "@simplewebauthn/typescript-types": "4.0.0", "@stripe/stripe-js": "1.15.0", "alphavantage": "2.2.0", "angular-material-css-vars": "2.1.2", diff --git a/yarn.lock b/yarn.lock index b5479a0c6..f31d5becb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2519,7 +2519,7 @@ consola "^2.15.0" node-fetch "^2.6.1" -"@peculiar/asn1-android@^2.0.26": +"@peculiar/asn1-android@^2.0.38": version "2.0.38" resolved "https://registry.yarnpkg.com/@peculiar/asn1-android/-/asn1-android-2.0.38.tgz#193281f5a232e323d6f2c069c7a8e8e8f4a994bd" integrity sha512-krWyggV6FgYf3fEPKVNjHVecLcQWlAu3/YhOyN+/L43dNKcsmqiEvuhqplh3aiXF62Ds0pqzqttWmdvoVqmSVQ== @@ -2528,7 +2528,7 @@ asn1js "^2.1.1" tslib "^2.3.0" -"@peculiar/asn1-schema@^2.0.26", "@peculiar/asn1-schema@^2.0.38": +"@peculiar/asn1-schema@^2.0.38": version "2.0.38" resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.0.38.tgz#98b6f12daad275ecd6774dfe31fb62f362900412" integrity sha512-zZ64UpCTm9me15nuCpPgJghSdbEm8atcDQPCyK+bKXjZAQ1735NCZXCSCfbckbQ4MH36Rm9403n/qMq77LFDzQ== @@ -2538,7 +2538,7 @@ pvtsutils "^1.2.0" tslib "^2.3.0" -"@peculiar/asn1-x509@^2.0.26": +"@peculiar/asn1-x509@^2.0.38": version "2.0.38" resolved "https://registry.yarnpkg.com/@peculiar/asn1-x509/-/asn1-x509-2.0.38.tgz#7ff3b5478d9c3784f0eb2fbe7693509da9de0a43" integrity sha512-10aK9fSxlc1DK9nEcwh+WPFNhAheXSE9RbI5MyS7FdBhgq+Mz4Z9JqFfaBZm1Qp+5mPtUMOP6cXVo7aaYlgq7A== @@ -2613,32 +2613,32 @@ "@angular-devkit/schematics" "12.1.4" jsonc-parser "3.0.0" -"@simplewebauthn/browser@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@simplewebauthn/browser/-/browser-3.0.0.tgz#3d76b199c9f474408a7ed75d86004423dd6ae38a" - integrity sha512-P661gZX/QW0Rg2NRAMtW84Q3u4nhXkPef9LLU4btLJFYoXO8RBFfxcmyqwyf2QEb4B7+lFdp5EWfZV5T7FvuHw== +"@simplewebauthn/browser@4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@simplewebauthn/browser/-/browser-4.1.0.tgz#3e7fd66729405d6a2a2a187c93577b90a8e41786" + integrity sha512-tIsEfShC1rrqrsNb44tOFuSriAFCz4tkdDnCjHfn2rYxgz+t+yqEvuIRfJHQpFrWSnZPdsjrAHtasj6lzfGI6w== -"@simplewebauthn/server@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@simplewebauthn/server/-/server-3.0.0.tgz#eb1a5bbe2ecdda54363b178f4bb3e134f25641f0" - integrity sha512-ymGX2obBrhY9R3OxrpCYaNGAovFHmMlQrGoNdVOe2R2JUBXC1Rg5JEUl1lGyaRykN1SyZqLgz86wAjDVuRITTA== +"@simplewebauthn/server@4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@simplewebauthn/server/-/server-4.1.0.tgz#9ad2e32cffa83833ff8a633775b2ace5e6926fa0" + integrity sha512-52X5/U+5Fo0XYG1TuBBGgG0ap9c0ffpeq0GZfFio/DZDW4He0Arb7Q/XkHw96JK0X1sfRKNmnfC+NImplvIimA== dependencies: - "@peculiar/asn1-android" "^2.0.26" - "@peculiar/asn1-schema" "^2.0.26" - "@peculiar/asn1-x509" "^2.0.26" - "@simplewebauthn/typescript-types" "^3.0.0" + "@peculiar/asn1-android" "^2.0.38" + "@peculiar/asn1-schema" "^2.0.38" + "@peculiar/asn1-x509" "^2.0.38" + "@simplewebauthn/typescript-types" "^4.0.0" base64url "^3.0.1" cbor "^5.1.0" elliptic "^6.5.3" - jsrsasign "^10.2.0" + jsrsasign "^10.4.0" jwk-to-pem "^2.0.4" node-fetch "^2.6.0" node-rsa "^1.1.1" -"@simplewebauthn/typescript-types@3.0.0", "@simplewebauthn/typescript-types@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@simplewebauthn/typescript-types/-/typescript-types-3.0.0.tgz#6712e9619d860f54f571cd27dbe167b2d9e5ab87" - integrity sha512-bsk3EQWzPOZwP9C+ETVhcFDpZywY5sTqmNuGkNm3aNpc9Xh/mqZjy8nL0Sm7xwrlhY0zWAlOaIWQ3LvN5SoFhg== +"@simplewebauthn/typescript-types@4.0.0", "@simplewebauthn/typescript-types@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@simplewebauthn/typescript-types/-/typescript-types-4.0.0.tgz#46ae4e69cb07305c57093a3ed99555437dfe0d49" + integrity sha512-jqQ0bCeBO96CytB397vSrQ8ipozQzAmI57izA7izyglyu35JBV90I7+75fSX+ZGNHmMwDNnA3EGYtBLOIpkJEg== "@sinonjs/commons@^1.7.0": version "1.8.3" @@ -11343,7 +11343,7 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -jsrsasign@^10.2.0: +jsrsasign@^10.4.0: version "10.4.0" resolved "https://registry.yarnpkg.com/jsrsasign/-/jsrsasign-10.4.0.tgz#362cc787079c03a363a958c03eb68d8545ba92f7" integrity sha512-C8qLhiAssh/b74KJpGhWuFGG9cFhJqMCVuuHXRibb3Z5vPuAW0ue0jUirpoExCdpdhv4nD3sZ1DAwJURYJTm9g==