diff --git a/internal/handlers/handler_register_webauthn.go b/internal/handlers/handler_register_webauthn.go index dbd9f4d7d..539ec6e0f 100644 --- a/internal/handlers/handler_register_webauthn.go +++ b/internal/handlers/handler_register_webauthn.go @@ -15,28 +15,6 @@ import ( "github.com/authelia/authelia/v4/internal/storage" ) -// WebauthnIdentityStart the handler for initiating the identity validation. -var WebauthnIdentityStart = middlewares.IdentityVerificationStart( - middlewares.IdentityVerificationStartArgs{ - MailTitle: "Register your key", - MailButtonContent: "Register", - TargetEndpoint: "/webauthn/register", - ActionClaim: ActionWebauthnRegistration, - IdentityRetrieverFunc: identityRetrieverFromSession, - }, nil) - -// WebauthnIdentityFinish the handler for finishing the identity validation. -var WebauthnIdentityFinish = middlewares.IdentityVerificationFinish( - middlewares.IdentityVerificationFinishArgs{ - ActionClaim: ActionWebauthnRegistration, - IsTokenUserValidFunc: isTokenUserValidFor2FARegistration, - }, WebauthnAttestationGET) - -// WebauthnAttestationGET returns the attestation challenge from the server. -func WebauthnAttestationGET(ctx *middlewares.AutheliaCtx, _ string) { - WebauthnRegistrationGET(ctx) -} - // WebauthnRegistrationGET returns the attestation challenge from the server. func WebauthnRegistrationGET(ctx *middlewares.AutheliaCtx) { var ( @@ -113,7 +91,7 @@ func WebauthnRegistrationPOST(ctx *middlewares.AutheliaCtx) { ) if userSession, err = ctx.GetSession(); err != nil { - ctx.Logger.WithError(err).Errorf("Error occurred retrieving session for %s attestation response", regulation.AuthTypeWebauthn) + ctx.Logger.WithError(err).Errorf("Error occurred retrieving session for %s registration response", regulation.AuthTypeWebauthn) respondUnauthorized(ctx, messageUnableToRegisterSecurityKey) @@ -121,7 +99,7 @@ func WebauthnRegistrationPOST(ctx *middlewares.AutheliaCtx) { } if userSession.Webauthn == nil { - ctx.Logger.Errorf("Webauthn session data is not present in order to handle attestation for user '%s'. This could indicate a user trying to POST to the wrong endpoint, or the session data is not present for the browser they used.", userSession.Username) + ctx.Logger.Errorf("Webauthn session data is not present in order to handle %s registration for user '%s'. This could indicate a user trying to POST to the wrong endpoint, or the session data is not present for the browser they used.", regulation.AuthTypeWebauthn, userSession.Username) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -129,7 +107,7 @@ func WebauthnRegistrationPOST(ctx *middlewares.AutheliaCtx) { } if w, err = newWebauthn(ctx); err != nil { - ctx.Logger.Errorf("Unable to configure %s during assertion challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) + ctx.Logger.Errorf("Unable to configure %s during registration for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) respondUnauthorized(ctx, messageUnableToRegisterSecurityKey) @@ -137,7 +115,7 @@ func WebauthnRegistrationPOST(ctx *middlewares.AutheliaCtx) { } if err = json.Unmarshal(ctx.PostBody(), &bodyJSON); err != nil { - ctx.Logger.Errorf("Unable to parse %s assertion request data for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) + ctx.Logger.Errorf("Unable to parse %s registration request POST data for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -145,7 +123,7 @@ func WebauthnRegistrationPOST(ctx *middlewares.AutheliaCtx) { } if response, err = protocol.ParseCredentialCreationResponseBody(bytes.NewReader(bodyJSON.Response)); err != nil { - ctx.Logger.Errorf("Unable to parse %s assertion for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) + ctx.Logger.Errorf("Unable to parse %s registration for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -155,7 +133,7 @@ func WebauthnRegistrationPOST(ctx *middlewares.AutheliaCtx) { ctx.Logger.WithField("att_format", response.Response.AttestationObject.Format).Debug("Response Data") if user, err = getWebAuthnUser(ctx, userSession); err != nil { - ctx.Logger.Errorf("Unable to load %s devices for assertion challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) + ctx.Logger.Errorf("Unable to load %s user details for registration for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -163,7 +141,7 @@ func WebauthnRegistrationPOST(ctx *middlewares.AutheliaCtx) { } if credential, err = w.CreateCredential(user, *userSession.Webauthn, response); err != nil { - ctx.Logger.Errorf("Unable to load %s devices for assertion challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) + ctx.Logger.Errorf("Unable to create %s credential for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -196,7 +174,7 @@ func WebauthnRegistrationPOST(ctx *middlewares.AutheliaCtx) { device := model.NewWebauthnDeviceFromCredential(w.Config.RPID, userSession.Username, bodyJSON.Description, credential) if err = ctx.Providers.StorageProvider.SaveWebauthnDevice(ctx, device); err != nil { - ctx.Logger.Errorf("Unable to load %s devices for assertion challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) + ctx.Logger.Errorf("Unable to save %s device registration for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) respondUnauthorized(ctx, messageUnableToRegisterSecurityKey) @@ -205,7 +183,7 @@ func WebauthnRegistrationPOST(ctx *middlewares.AutheliaCtx) { userSession.Webauthn = nil if err = ctx.SaveSession(userSession); err != nil { - ctx.Logger.Errorf(logFmtErrSessionSave, "removal of the attestation challenge", regulation.AuthTypeWebauthn, userSession.Username, err) + ctx.Logger.Errorf(logFmtErrSessionSave, "removal of the registration challenge", regulation.AuthTypeWebauthn, userSession.Username, err) } ctx.ReplyOK() diff --git a/internal/handlers/handler_sign_webauthn.go b/internal/handlers/handler_sign_webauthn.go index 435002929..1bbaeb2fd 100644 --- a/internal/handlers/handler_sign_webauthn.go +++ b/internal/handlers/handler_sign_webauthn.go @@ -30,7 +30,7 @@ func WebauthnAssertionGET(ctx *middlewares.AutheliaCtx) { } if w, err = newWebauthn(ctx); err != nil { - ctx.Logger.Errorf("Unable to configure %s during assertion challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) + ctx.Logger.Errorf("Unable to configure %s during authentication challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -38,7 +38,7 @@ func WebauthnAssertionGET(ctx *middlewares.AutheliaCtx) { } if user, err = getWebAuthnUser(ctx, userSession); err != nil { - ctx.Logger.Errorf("Unable to create %s assertion challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) + ctx.Logger.Errorf("Unable to load %s user details during authentication challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -62,7 +62,7 @@ func WebauthnAssertionGET(ctx *middlewares.AutheliaCtx) { var assertion *protocol.CredentialAssertion if assertion, userSession.Webauthn, err = w.BeginLogin(user, opts...); err != nil { - ctx.Logger.Errorf("Unable to create %s assertion challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) + ctx.Logger.Errorf("Unable to create %s authentication challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -116,7 +116,7 @@ func WebauthnAssertionPOST(ctx *middlewares.AutheliaCtx) { } if userSession.Webauthn == nil { - ctx.Logger.Errorf("Webauthn session data is not present in order to handle assertion for user '%s'. This could indicate a user trying to POST to the wrong endpoint, or the session data is not present for the browser they used.", userSession.Username) + ctx.Logger.Errorf("Webauthn session data is not present in order to handle authentication challenge for user '%s'. This could indicate a user trying to POST to the wrong endpoint, or the session data is not present for the browser they used.", userSession.Username) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -124,7 +124,7 @@ func WebauthnAssertionPOST(ctx *middlewares.AutheliaCtx) { } if w, err = newWebauthn(ctx); err != nil { - ctx.Logger.Errorf("Unable to configure %s during assertion challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) + ctx.Logger.Errorf("Unable to configure %s during authentication challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -138,7 +138,7 @@ func WebauthnAssertionPOST(ctx *middlewares.AutheliaCtx) { ) if assertionResponse, err = protocol.ParseCredentialRequestResponseBody(bytes.NewReader(bodyJSON.Response)); err != nil { - ctx.Logger.Errorf("Unable to parse %s assertionfor user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) + ctx.Logger.Errorf("Unable to parse %s authentication challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -146,7 +146,7 @@ func WebauthnAssertionPOST(ctx *middlewares.AutheliaCtx) { } if user, err = getWebAuthnUser(ctx, userSession); err != nil { - ctx.Logger.Errorf("Unable to load %s devices for assertion challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) + ctx.Logger.Errorf("Unable to load %s credentials for authentication challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -170,7 +170,7 @@ func WebauthnAssertionPOST(ctx *middlewares.AutheliaCtx) { found = true if err = ctx.Providers.StorageProvider.UpdateWebauthnDeviceSignIn(ctx, device.ID, device.RPID, device.LastUsedAt, device.SignCount, device.CloneWarning); err != nil { - ctx.Logger.Errorf("Unable to save %s device signin count for assertion challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) + ctx.Logger.Errorf("Unable to save %s device signin count for authentication challenge for user '%s': %+v", regulation.AuthTypeWebauthn, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -182,7 +182,7 @@ func WebauthnAssertionPOST(ctx *middlewares.AutheliaCtx) { } if !found { - ctx.Logger.Errorf("Unable to save %s device signin count for assertion challenge for user '%s' device '%x' count '%d': unable to find device", regulation.AuthTypeWebauthn, userSession.Username, credential.ID, credential.Authenticator.SignCount) + ctx.Logger.Errorf("Unable to save %s device signin count for authentication challenge for user '%s' device '%x' count '%d': unable to find device", regulation.AuthTypeWebauthn, userSession.Username, credential.ID, credential.Authenticator.SignCount) respondUnauthorized(ctx, messageMFAValidationFailed) @@ -208,7 +208,7 @@ func WebauthnAssertionPOST(ctx *middlewares.AutheliaCtx) { assertionResponse.Response.AuthenticatorData.Flags.UserVerified()) if err = ctx.SaveSession(userSession); err != nil { - ctx.Logger.Errorf(logFmtErrSessionSave, "removal of the assertion challenge and authentication time", regulation.AuthTypeWebauthn, userSession.Username, err) + ctx.Logger.Errorf(logFmtErrSessionSave, "removal of the authentiation challenge and authentication time", regulation.AuthTypeWebauthn, userSession.Username, err) respondUnauthorized(ctx, messageMFAValidationFailed) diff --git a/internal/server/handlers.go b/internal/server/handlers.go index 645fa2a2e..a8496c037 100644 --- a/internal/server/handlers.go +++ b/internal/server/handlers.go @@ -235,22 +235,15 @@ func handleRouter(config schema.Configuration, providers middlewares.Providers) } if !config.Webauthn.Disable { - // Webauthn Endpoints. - r.POST("/api/secondfactor/webauthn/identity/start", middleware1FA(handlers.WebauthnIdentityStart)) - r.POST("/api/secondfactor/webauthn/identity/finish", middleware1FA(handlers.WebauthnIdentityFinish)) - - r.GET("/api/secondfactor/register/webauthn", middleware1FA(handlers.WebauthnRegistrationGET)) - r.POST("/api/secondfactor/register/webauthn", middleware1FA(handlers.WebauthnRegistrationPOST)) - - r.POST("/api/secondfactor/webauthn/attestation", middleware1FA(handlers.WebauthnRegistrationPOST)) - - r.GET("/api/secondfactor/webauthn/assertion", middleware1FA(handlers.WebauthnAssertionGET)) - r.POST("/api/secondfactor/webauthn/assertion", middleware1FA(handlers.WebauthnAssertionPOST)) + r.GET("/api/secondfactor/webauthn", middleware1FA(handlers.WebauthnAssertionGET)) + r.POST("/api/secondfactor/webauthn", middleware1FA(handlers.WebauthnAssertionPOST)) // Management of the webauthn devices. - r.GET("/api/secondfactor/webauthn/devices", middleware1FA(handlers.WebauthnDevicesGET)) - r.PUT("/api/secondfactor/webauthn/device/{deviceID}", middleware2FA(handlers.WebauthnDevicePUT)) - r.DELETE("/api/secondfactor/webauthn/device/{deviceID}", middleware2FA(handlers.WebauthnDeviceDELETE)) + r.GET("/api/secondfactor/webauthn/credentials", middleware1FA(handlers.WebauthnDevicesGET)) + r.GET("/api/secondfactor/webauthn/credential/register", middleware1FA(handlers.WebauthnRegistrationGET)) + r.POST("/api/secondfactor/webauthn/credential/register", middleware1FA(handlers.WebauthnRegistrationPOST)) + r.PUT("/api/secondfactor/webauthn/credential/{deviceID}", middleware2FA(handlers.WebauthnDevicePUT)) + r.DELETE("/api/secondfactor/webauthn/credential/{deviceID}", middleware2FA(handlers.WebauthnDeviceDELETE)) } // Configure DUO api endpoint only if configuration exists. diff --git a/web/package.json b/web/package.json index 7c1b7b1ee..79dec9434 100644 --- a/web/package.json +++ b/web/package.json @@ -28,8 +28,8 @@ "@mui/icons-material": "5.11.0", "@mui/material": "5.11.6", "@mui/styles": "5.11.2", - "@simplewebauthn/browser": "^7.0.1", - "@simplewebauthn/typescript-types": "^7.0.0", + "@simplewebauthn/browser": "7.0.1", + "@simplewebauthn/typescript-types": "7.0.0", "axios": "1.2.6", "broadcast-channel": "4.20.2", "classnames": "2.3.2", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index f3d9d3822..20aec5b53 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -14,8 +14,8 @@ specifiers: '@mui/icons-material': 5.11.0 '@mui/material': 5.11.6 '@mui/styles': 5.11.2 - '@simplewebauthn/browser': ^7.0.1 - '@simplewebauthn/typescript-types': ^7.0.0 + '@simplewebauthn/browser': 7.0.1 + '@simplewebauthn/typescript-types': 7.0.0 '@testing-library/jest-dom': 5.16.5 '@testing-library/react': 13.4.0 '@types/jest': 29.4.0 @@ -504,7 +504,6 @@ packages: /@babel/parser/7.20.7: resolution: {integrity: sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==} engines: {node: '>=6.0.0'} - hasBin: true dependencies: '@babel/types': 7.20.7 dev: true @@ -2021,7 +2020,6 @@ packages: /@cnakazawa/watch/1.0.4: resolution: {integrity: sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==} engines: {node: '>=0.1.95'} - hasBin: true dependencies: exec-sh: 0.3.6 minimist: 1.2.6 @@ -2030,7 +2028,6 @@ packages: /@commitlint/cli/17.4.2: resolution: {integrity: sha512-0rPGJ2O1owhpxMIXL9YJ2CgPkdrFLKZElIZHXDN8L8+qWK1DGH7Q7IelBT1pchXTYTuDlqkOTdh//aTvT3bSUA==} engines: {node: '>=v14'} - hasBin: true dependencies: '@commitlint/format': 17.4.0 '@commitlint/lint': 17.4.2 @@ -4042,7 +4039,6 @@ packages: /JSONStream/1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} - hasBin: true dependencies: jsonparse: 1.3.1 through: 2.3.8 @@ -4080,13 +4076,11 @@ packages: /acorn/7.4.1: resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} engines: {node: '>=0.4.0'} - hasBin: true dev: true /acorn/8.8.0: resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==} engines: {node: '>=0.4.0'} - hasBin: true dev: true /agent-base/6.0.2: @@ -4290,7 +4284,6 @@ packages: /atob/2.1.2: resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} engines: {node: '>= 4.5.0'} - hasBin: true dev: true /available-typed-arrays/1.0.5: @@ -4620,7 +4613,6 @@ packages: /browserslist/4.21.4: resolution: {integrity: sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true dependencies: caniuse-lite: 1.0.30001425 electron-to-chromium: 1.4.284 @@ -4852,7 +4844,6 @@ packages: /conventional-commits-parser/3.2.4: resolution: {integrity: sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==} engines: {node: '>=10'} - hasBin: true dependencies: JSONStream: 1.3.5 is-text-path: 1.0.1 @@ -5303,7 +5294,6 @@ packages: /esbuild/0.16.17: resolution: {integrity: sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==} engines: {node: '>=12'} - hasBin: true requiresBuild: true optionalDependencies: '@esbuild/android-arm': 0.16.17 @@ -5333,7 +5323,6 @@ packages: /esbuild/0.17.5: resolution: {integrity: sha512-Bu6WLCc9NMsNoMJUjGl3yBzTjVLXdysMltxQWiLAypP+/vQrf+3L1Xe8fCXzxaECus2cEJ9M7pk4yKatEwQMqQ==} engines: {node: '>=12'} - hasBin: true requiresBuild: true optionalDependencies: '@esbuild/android-arm': 0.17.5 @@ -5381,7 +5370,6 @@ packages: /escodegen/2.0.0: resolution: {integrity: sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==} engines: {node: '>=6.0'} - hasBin: true dependencies: esprima: 4.0.1 estraverse: 5.3.0 @@ -5393,7 +5381,6 @@ packages: /eslint-config-prettier/8.6.0_eslint@8.33.0: resolution: {integrity: sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==} - hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: @@ -5699,7 +5686,6 @@ packages: /eslint/8.33.0: resolution: {integrity: sha512-WjOpFQgKK8VrCnAtl8We0SUOy/oVZ5NHykyMiagV1M9r8IFpIJX7DduK6n1mpfhlG7T1NLWm2SuD8QB7KFySaA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true dependencies: '@eslint/eslintrc': 1.4.1 '@humanwhocodes/config-array': 0.11.8 @@ -5756,7 +5742,6 @@ packages: /esprima/4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} - hasBin: true dev: true /esquery/1.4.0: @@ -6133,7 +6118,6 @@ packages: /git-raw-commits/2.0.11: resolution: {integrity: sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A==} engines: {node: '>=10'} - hasBin: true dependencies: dargs: 7.0.0 lodash: 4.17.21 @@ -6366,7 +6350,6 @@ packages: /husky/8.0.3: resolution: {integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==} engines: {node: '>=14'} - hasBin: true dev: true /hyphenate-style-name/1.0.4: @@ -6415,7 +6398,6 @@ packages: /import-local/3.1.0: resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} engines: {node: '>=8'} - hasBin: true dependencies: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 @@ -6511,7 +6493,6 @@ packages: /is-ci/2.0.0: resolution: {integrity: sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==} - hasBin: true dependencies: ci-info: 2.0.0 dev: true @@ -6569,7 +6550,6 @@ packages: /is-docker/2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} - hasBin: true dev: true /is-extendable/0.1.1: @@ -6865,7 +6845,6 @@ packages: /jest-cli/29.4.1_@types+node@18.11.18: resolution: {integrity: sha512-jz7GDIhtxQ37M+9dlbv5K+/FVcIo1O/b1sX3cJgzlQUf/3VG25nvuWzlDC4F1FLLzUThJeWLu8I7JF9eWpuURQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: @@ -7334,7 +7313,6 @@ packages: /jest/29.4.1_@types+node@18.11.18: resolution: {integrity: sha512-cknimw7gAXPDOmj0QqztlxVtBVCw2lYY9CeIE5N6kD+kET1H4H79HSNISJmijb1HF+qk+G+ploJgiDi5k/fRlg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: @@ -7360,7 +7338,6 @@ packages: /js-yaml/3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true dependencies: argparse: 1.0.10 esprima: 4.0.1 @@ -7368,7 +7345,6 @@ packages: /js-yaml/4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true dependencies: argparse: 2.0.1 dev: true @@ -7417,13 +7393,11 @@ packages: /jsesc/0.5.0: resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} - hasBin: true dev: true /jsesc/2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} - hasBin: true dev: true /json-parse-even-better-errors/2.3.1: @@ -7443,7 +7417,6 @@ packages: /json5/1.0.1: resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==} - hasBin: true dependencies: minimist: 1.2.6 dev: true @@ -7451,7 +7424,6 @@ packages: /json5/2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} - hasBin: true dev: true /jsonfile/6.1.0: @@ -7664,7 +7636,6 @@ packages: /loose-envify/1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true dependencies: js-tokens: 4.0.0 @@ -7683,7 +7654,6 @@ packages: /lz-string/1.4.4: resolution: {integrity: sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==} - hasBin: true dev: true /magic-string/0.27.0: @@ -7848,7 +7818,6 @@ packages: /nanoid/3.3.4: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true dev: true /nanomatch/1.2.13: @@ -8247,7 +8216,6 @@ packages: /prettier/2.8.3: resolution: {integrity: sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==} engines: {node: '>=10.13.0'} - hasBin: true dev: true /pretty-format/27.5.1: @@ -8560,7 +8528,6 @@ packages: /regjsparser/0.8.4: resolution: {integrity: sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==} - hasBin: true dependencies: jsesc: 0.5.0 dev: true @@ -8614,7 +8581,6 @@ packages: /resolve-url/0.2.1: resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} - deprecated: https://github.com/lydell/resolve-url#deprecated dev: true /resolve.exports/2.0.0: @@ -8624,7 +8590,6 @@ packages: /resolve/1.22.1: resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} - hasBin: true dependencies: is-core-module: 2.11.0 path-parse: 1.0.7 @@ -8632,7 +8597,6 @@ packages: /resolve/2.0.0-next.4: resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} - hasBin: true dependencies: is-core-module: 2.11.0 path-parse: 1.0.7 @@ -8651,14 +8615,12 @@ packages: /rimraf/3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - hasBin: true dependencies: glob: 7.2.3 /rollup/2.78.0: resolution: {integrity: sha512-4+YfbQC9QEVvKTanHhIAFVUFSRsezvQF8vFOJwtGfb9Bb+r014S+qryr9PSmw8x6sMnPkmFBGAvIFVQxvJxjtg==} engines: {node: '>=10.0.0'} - hasBin: true optionalDependencies: fsevents: 2.3.2 dev: true @@ -8666,7 +8628,6 @@ packages: /rollup/3.7.4: resolution: {integrity: sha512-jN9rx3k5pfg9H9al0r0y1EYKSeiRANZRYX32SuNXAnKzh6cVyf4LZVto1KAuDnbHT03E1CpsgqDKaqQ8FZtgxw==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} - hasBin: true optionalDependencies: fsevents: 2.3.2 dev: true @@ -8710,8 +8671,6 @@ packages: /sane/4.1.0: resolution: {integrity: sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==} engines: {node: 6.* || 8.* || >= 10.*} - deprecated: some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added - hasBin: true dependencies: '@cnakazawa/watch': 1.0.4 anymatch: 2.0.0 @@ -8740,23 +8699,19 @@ packages: /semver/5.7.1: resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} - hasBin: true dev: true /semver/6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} - hasBin: true dev: true /semver/7.0.0: resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==} - hasBin: true dev: true /semver/7.3.8: resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} engines: {node: '>=10'} - hasBin: true dependencies: lru-cache: 6.0.0 dev: true @@ -8865,7 +8820,6 @@ packages: /source-map-resolve/0.5.3: resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} - deprecated: See https://github.com/lydell/source-map-resolve#deprecated dependencies: atob: 2.1.2 decode-uri-component: 0.2.2 @@ -8883,7 +8837,6 @@ packages: /source-map-url/0.4.1: resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} - deprecated: See https://github.com/lydell/source-map-url#deprecated dev: true /source-map/0.5.7: @@ -9214,7 +9167,6 @@ packages: /ts-node/10.9.0_awa2wsr5thmg3i7jqycphctjfq: resolution: {integrity: sha512-bunW18GUyaCSYRev4DPf4SQpom3pWH29wKl0sDk5zE7ze19RImEVhCW7K4v3hHKkUyfWotU08ToE2RS+Y49aug==} - hasBin: true peerDependencies: '@swc/core': '>=1.2.50' '@swc/wasm': '>=1.2.50' @@ -9246,7 +9198,6 @@ packages: /tsconfck/2.0.1_typescript@4.9.4: resolution: {integrity: sha512-/ipap2eecmVBmBlsQLBRbUmUNFwNJV/z2E+X0FPtHNjPwroMZQ7m39RMaCywlCulBheYXgMdUlWDd9rzxwMA0Q==} engines: {node: ^14.13.1 || ^16 || >=18, pnpm: ^7.0.1} - hasBin: true peerDependencies: typescript: ^4.3.5 peerDependenciesMeta: @@ -9341,7 +9292,6 @@ packages: /typescript/4.9.4: resolution: {integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==} engines: {node: '>=4.2.0'} - hasBin: true dev: true /unbox-primitive/1.0.2: @@ -9410,7 +9360,6 @@ packages: /update-browserslist-db/1.0.10_browserslist@4.21.4: resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} - hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: @@ -9427,7 +9376,6 @@ packages: /urix/0.1.0: resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} - deprecated: Please see https://github.com/lydell/urix#deprecated dev: true /use/3.1.1: @@ -9513,7 +9461,6 @@ packages: /vite/4.0.4_@types+node@18.11.18: resolution: {integrity: sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==} engines: {node: ^14.18.0 || >=16.0.0} - hasBin: true peerDependencies: '@types/node': '>= 14' less: '*' @@ -9551,7 +9498,6 @@ packages: /w3c-hr-time/1.0.2: resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} - deprecated: Use your platform's native performance.now() and performance.timeOrigin. dependencies: browser-process-hrtime: 1.0.0 dev: true @@ -9638,7 +9584,6 @@ packages: /which/1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} - hasBin: true dependencies: isexe: 2.0.0 dev: true @@ -9646,7 +9591,6 @@ packages: /which/2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} - hasBin: true dependencies: isexe: 2.0.0 dev: true diff --git a/web/src/services/Api.ts b/web/src/services/Api.ts index 338963bf3..1e0d660df 100644 --- a/web/src/services/Api.ts +++ b/web/src/services/Api.ts @@ -11,13 +11,12 @@ export const FirstFactorPath = basePath + "/api/firstfactor"; export const InitiateTOTPRegistrationPath = basePath + "/api/secondfactor/totp/identity/start"; export const CompleteTOTPRegistrationPath = basePath + "/api/secondfactor/totp/identity/finish"; -export const WebauthnIdentityStartPath = basePath + "/api/secondfactor/webauthn/identity/start"; -export const WebauthnRegistrationPath = basePath + "/api/secondfactor/register/webauthn"; +export const WebauthnRegistrationPath = basePath + "/api/secondfactor/webauthn/credential/register"; -export const WebauthnAssertionPath = basePath + "/api/secondfactor/webauthn/assertion"; +export const WebauthnAssertionPath = basePath + "/api/secondfactor/webauthn"; -export const WebauthnDevicesPath = basePath + "/api/secondfactor/webauthn/devices"; -export const WebauthnDevicePath = basePath + "/api/secondfactor/webauthn/device"; +export const WebauthnDevicesPath = basePath + "/api/secondfactor/webauthn/credentials"; +export const WebauthnDevicePath = basePath + "/api/secondfactor/webauthn/credential"; export const InitiateDuoDeviceSelectionPath = basePath + "/api/secondfactor/duo_devices"; export const CompleteDuoDeviceSelectionPath = basePath + "/api/secondfactor/duo_device"; diff --git a/web/src/services/RegisterDevice.ts b/web/src/services/RegisterDevice.ts index 431b336af..0524f6235 100644 --- a/web/src/services/RegisterDevice.ts +++ b/web/src/services/RegisterDevice.ts @@ -1,4 +1,4 @@ -import { CompleteTOTPRegistrationPath, InitiateTOTPRegistrationPath, WebauthnIdentityStartPath } from "@services/Api"; +import { CompleteTOTPRegistrationPath, InitiateTOTPRegistrationPath } from "@services/Api"; import { Post, PostWithOptionalResponse } from "@services/Client"; export async function initiateTOTPRegistrationProcess() { @@ -13,7 +13,3 @@ interface CompleteTOTPRegistrationResponse { export async function completeTOTPRegistrationProcess(processToken: string) { return Post(CompleteTOTPRegistrationPath, { token: processToken }); } - -export async function initiateWebauthnRegistrationProcess() { - return PostWithOptionalResponse(WebauthnIdentityStartPath); -} diff --git a/web/src/views/Settings/TwoFactorAuthentication/WebauthnDevices.tsx b/web/src/views/Settings/TwoFactorAuthentication/WebauthnDevices.tsx index 55f446ed5..c1e60ead6 100644 --- a/web/src/views/Settings/TwoFactorAuthentication/WebauthnDevices.tsx +++ b/web/src/views/Settings/TwoFactorAuthentication/WebauthnDevices.tsx @@ -1,13 +1,10 @@ -import React, { Fragment, Suspense, useState } from "react"; +import React, { Fragment, Suspense } from "react"; import { Box, Button, Paper, Stack, Typography } from "@mui/material"; -import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; import { RegisterWebauthnRoute } from "@constants/Routes"; -import { useNotifications } from "@hooks/NotificationsContext"; -import { initiateWebauthnRegistrationProcess } from "@services/RegisterDevice"; -import { AutheliaState, AuthenticationLevel } from "@services/State"; +import { AutheliaState } from "@services/State"; import LoadingPage from "@views/LoadingPage/LoadingPage"; import WebauthnDevicesStack from "@views/Settings/TwoFactorAuthentication/WebauthnDevicesStack"; @@ -16,33 +13,14 @@ interface Props { } export default function WebauthnDevices(props: Props) { - const { t: translate } = useTranslation("settings"); const navigate = useNavigate(); - const { createInfoNotification, createErrorNotification } = useNotifications(); - const [registrationInProgress, setRegistrationInProgress] = useState(false); - - const initiateRegistration = async (initiateRegistrationFunc: () => Promise, redirectRoute: string) => { - if (props.state.authentication_level >= AuthenticationLevel.TwoFactor) { - navigate(redirectRoute); - } else { - if (registrationInProgress) { - return; - } - setRegistrationInProgress(true); - try { - await initiateRegistrationFunc(); - createInfoNotification(translate("An email has been sent to your address to complete the process")); - } catch (err) { - console.error(err); - createErrorNotification(translate("There was a problem initiating the registration process")); - } - setRegistrationInProgress(false); - } + const initiateRegistration = async (redirectRoute: string) => { + navigate(redirectRoute); }; const handleAddKeyButtonClick = () => { - initiateRegistration(initiateWebauthnRegistrationProcess, RegisterWebauthnRoute); + initiateRegistration(RegisterWebauthnRoute); }; return (