You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-08-06 06:02:40 +03:00
frontend: password recovery
This commit is contained in:
committed by
reivilibre
parent
6613f4547a
commit
a6d46d90ca
@@ -6,7 +6,8 @@
|
|||||||
"close": "Close",
|
"close": "Close",
|
||||||
"continue": "Continue",
|
"continue": "Continue",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"save": "Save"
|
"save": "Save",
|
||||||
|
"save_and_continue": "Save and continue"
|
||||||
},
|
},
|
||||||
"branding": {
|
"branding": {
|
||||||
"privacy_policy": {
|
"privacy_policy": {
|
||||||
@@ -135,6 +136,9 @@
|
|||||||
},
|
},
|
||||||
"title": "Change your password"
|
"title": "Change your password"
|
||||||
},
|
},
|
||||||
|
"password_reset": {
|
||||||
|
"title": "Reset your password"
|
||||||
|
},
|
||||||
"password_strength": {
|
"password_strength": {
|
||||||
"placeholder": "Password strength",
|
"placeholder": "Password strength",
|
||||||
"score": {
|
"score": {
|
||||||
|
@@ -55,6 +55,8 @@ const documents = {
|
|||||||
"\n query VerifyEmailQuery($id: ID!) {\n userEmail(id: $id) {\n ...UserEmail_verifyEmail\n }\n }\n": types.VerifyEmailQueryDocument,
|
"\n query VerifyEmailQuery($id: ID!) {\n userEmail(id: $id) {\n ...UserEmail_verifyEmail\n }\n }\n": types.VerifyEmailQueryDocument,
|
||||||
"\n query PasswordChangeQuery {\n viewer {\n __typename\n ... on Node {\n id\n }\n }\n\n siteConfig {\n ...PasswordCreationDoubleInput_siteConfig\n }\n }\n": types.PasswordChangeQueryDocument,
|
"\n query PasswordChangeQuery {\n viewer {\n __typename\n ... on Node {\n id\n }\n }\n\n siteConfig {\n ...PasswordCreationDoubleInput_siteConfig\n }\n }\n": types.PasswordChangeQueryDocument,
|
||||||
"\n mutation ChangePassword(\n $userId: ID!\n $oldPassword: String!\n $newPassword: String!\n ) {\n setPassword(\n input: {\n userId: $userId\n currentPassword: $oldPassword\n newPassword: $newPassword\n }\n ) {\n status\n }\n }\n": types.ChangePasswordDocument,
|
"\n mutation ChangePassword(\n $userId: ID!\n $oldPassword: String!\n $newPassword: String!\n ) {\n setPassword(\n input: {\n userId: $userId\n currentPassword: $oldPassword\n newPassword: $newPassword\n }\n ) {\n status\n }\n }\n": types.ChangePasswordDocument,
|
||||||
|
"\n query PasswordRecoveryQuery {\n siteConfig {\n id\n ...PasswordCreationDoubleInput_siteConfig\n }\n }\n": types.PasswordRecoveryQueryDocument,
|
||||||
|
"\n mutation RecoverPassword($ticket: String!, $newPassword: String!) {\n setPasswordByRecovery(\n input: { ticket: $ticket, newPassword: $newPassword }\n ) {\n status\n }\n }\n": types.RecoverPasswordDocument,
|
||||||
"\n mutation AllowCrossSigningReset($userId: ID!) {\n allowUserCrossSigningReset(input: { userId: $userId }) {\n user {\n id\n }\n }\n }\n": types.AllowCrossSigningResetDocument,
|
"\n mutation AllowCrossSigningReset($userId: ID!) {\n allowUserCrossSigningReset(input: { userId: $userId }) {\n user {\n id\n }\n }\n }\n": types.AllowCrossSigningResetDocument,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -240,6 +242,14 @@ export function graphql(source: "\n query PasswordChangeQuery {\n viewer {\n
|
|||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
export function graphql(source: "\n mutation ChangePassword(\n $userId: ID!\n $oldPassword: String!\n $newPassword: String!\n ) {\n setPassword(\n input: {\n userId: $userId\n currentPassword: $oldPassword\n newPassword: $newPassword\n }\n ) {\n status\n }\n }\n"): (typeof documents)["\n mutation ChangePassword(\n $userId: ID!\n $oldPassword: String!\n $newPassword: String!\n ) {\n setPassword(\n input: {\n userId: $userId\n currentPassword: $oldPassword\n newPassword: $newPassword\n }\n ) {\n status\n }\n }\n"];
|
export function graphql(source: "\n mutation ChangePassword(\n $userId: ID!\n $oldPassword: String!\n $newPassword: String!\n ) {\n setPassword(\n input: {\n userId: $userId\n currentPassword: $oldPassword\n newPassword: $newPassword\n }\n ) {\n status\n }\n }\n"): (typeof documents)["\n mutation ChangePassword(\n $userId: ID!\n $oldPassword: String!\n $newPassword: String!\n ) {\n setPassword(\n input: {\n userId: $userId\n currentPassword: $oldPassword\n newPassword: $newPassword\n }\n ) {\n status\n }\n }\n"];
|
||||||
|
/**
|
||||||
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
|
*/
|
||||||
|
export function graphql(source: "\n query PasswordRecoveryQuery {\n siteConfig {\n id\n ...PasswordCreationDoubleInput_siteConfig\n }\n }\n"): (typeof documents)["\n query PasswordRecoveryQuery {\n siteConfig {\n id\n ...PasswordCreationDoubleInput_siteConfig\n }\n }\n"];
|
||||||
|
/**
|
||||||
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
|
*/
|
||||||
|
export function graphql(source: "\n mutation RecoverPassword($ticket: String!, $newPassword: String!) {\n setPasswordByRecovery(\n input: { ticket: $ticket, newPassword: $newPassword }\n ) {\n status\n }\n }\n"): (typeof documents)["\n mutation RecoverPassword($ticket: String!, $newPassword: String!) {\n setPasswordByRecovery(\n input: { ticket: $ticket, newPassword: $newPassword }\n ) {\n status\n }\n }\n"];
|
||||||
/**
|
/**
|
||||||
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
|
||||||
*/
|
*/
|
||||||
|
@@ -1694,6 +1694,22 @@ export type ChangePasswordMutationVariables = Exact<{
|
|||||||
|
|
||||||
export type ChangePasswordMutation = { __typename?: 'Mutation', setPassword: { __typename?: 'SetPasswordPayload', status: SetPasswordStatus } };
|
export type ChangePasswordMutation = { __typename?: 'Mutation', setPassword: { __typename?: 'SetPasswordPayload', status: SetPasswordStatus } };
|
||||||
|
|
||||||
|
export type PasswordRecoveryQueryQueryVariables = Exact<{ [key: string]: never; }>;
|
||||||
|
|
||||||
|
|
||||||
|
export type PasswordRecoveryQueryQuery = { __typename?: 'Query', siteConfig: (
|
||||||
|
{ __typename?: 'SiteConfig', id: string }
|
||||||
|
& { ' $fragmentRefs'?: { 'PasswordCreationDoubleInput_SiteConfigFragment': PasswordCreationDoubleInput_SiteConfigFragment } }
|
||||||
|
) };
|
||||||
|
|
||||||
|
export type RecoverPasswordMutationVariables = Exact<{
|
||||||
|
ticket: Scalars['String']['input'];
|
||||||
|
newPassword: Scalars['String']['input'];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
|
||||||
|
export type RecoverPasswordMutation = { __typename?: 'Mutation', setPasswordByRecovery: { __typename?: 'SetPasswordPayload', status: SetPasswordStatus } };
|
||||||
|
|
||||||
export type AllowCrossSigningResetMutationVariables = Exact<{
|
export type AllowCrossSigningResetMutationVariables = Exact<{
|
||||||
userId: Scalars['ID']['input'];
|
userId: Scalars['ID']['input'];
|
||||||
}>;
|
}>;
|
||||||
@@ -1743,4 +1759,6 @@ export const DeviceRedirectQueryDocument = {"kind":"Document","definitions":[{"k
|
|||||||
export const VerifyEmailQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"VerifyEmailQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userEmail"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"UserEmail_verifyEmail"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"UserEmail_verifyEmail"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"UserEmail"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}}]}}]} as unknown as DocumentNode<VerifyEmailQueryQuery, VerifyEmailQueryQueryVariables>;
|
export const VerifyEmailQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"VerifyEmailQuery"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userEmail"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"UserEmail_verifyEmail"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"UserEmail_verifyEmail"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"UserEmail"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}}]}}]} as unknown as DocumentNode<VerifyEmailQueryQuery, VerifyEmailQueryQueryVariables>;
|
||||||
export const PasswordChangeQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PasswordChangeQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"viewer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"siteConfig"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PasswordCreationDoubleInput_siteConfig"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PasswordCreationDoubleInput_siteConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SiteConfig"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"minimumPasswordComplexity"}}]}}]} as unknown as DocumentNode<PasswordChangeQueryQuery, PasswordChangeQueryQueryVariables>;
|
export const PasswordChangeQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PasswordChangeQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"viewer"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"__typename"}},{"kind":"InlineFragment","typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Node"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"siteConfig"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"PasswordCreationDoubleInput_siteConfig"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PasswordCreationDoubleInput_siteConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SiteConfig"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"minimumPasswordComplexity"}}]}}]} as unknown as DocumentNode<PasswordChangeQueryQuery, PasswordChangeQueryQueryVariables>;
|
||||||
export const ChangePasswordDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ChangePassword"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"userId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oldPassword"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"newPassword"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setPassword"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"userId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"userId"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"currentPassword"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oldPassword"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"newPassword"},"value":{"kind":"Variable","name":{"kind":"Name","value":"newPassword"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]} as unknown as DocumentNode<ChangePasswordMutation, ChangePasswordMutationVariables>;
|
export const ChangePasswordDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ChangePassword"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"userId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"oldPassword"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"newPassword"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setPassword"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"userId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"userId"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"currentPassword"},"value":{"kind":"Variable","name":{"kind":"Name","value":"oldPassword"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"newPassword"},"value":{"kind":"Variable","name":{"kind":"Name","value":"newPassword"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]} as unknown as DocumentNode<ChangePasswordMutation, ChangePasswordMutationVariables>;
|
||||||
|
export const PasswordRecoveryQueryDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PasswordRecoveryQuery"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"siteConfig"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"PasswordCreationDoubleInput_siteConfig"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PasswordCreationDoubleInput_siteConfig"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"SiteConfig"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"minimumPasswordComplexity"}}]}}]} as unknown as DocumentNode<PasswordRecoveryQueryQuery, PasswordRecoveryQueryQueryVariables>;
|
||||||
|
export const RecoverPasswordDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RecoverPassword"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"ticket"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"newPassword"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setPasswordByRecovery"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"ticket"},"value":{"kind":"Variable","name":{"kind":"Name","value":"ticket"}}},{"kind":"ObjectField","name":{"kind":"Name","value":"newPassword"},"value":{"kind":"Variable","name":{"kind":"Name","value":"newPassword"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]} as unknown as DocumentNode<RecoverPasswordMutation, RecoverPasswordMutationVariables>;
|
||||||
export const AllowCrossSigningResetDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AllowCrossSigningReset"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"userId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"allowUserCrossSigningReset"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"userId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"userId"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode<AllowCrossSigningResetMutation, AllowCrossSigningResetMutationVariables>;
|
export const AllowCrossSigningResetDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AllowCrossSigningReset"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"userId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"allowUserCrossSigningReset"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"userId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"userId"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode<AllowCrossSigningResetMutation, AllowCrossSigningResetMutationVariables>;
|
@@ -16,6 +16,7 @@ import { Route as AccountImport } from './routes/_account'
|
|||||||
import { Route as AccountIndexImport } from './routes/_account.index'
|
import { Route as AccountIndexImport } from './routes/_account.index'
|
||||||
import { Route as DevicesSplatImport } from './routes/devices.$'
|
import { Route as DevicesSplatImport } from './routes/devices.$'
|
||||||
import { Route as ClientsIdImport } from './routes/clients.$id'
|
import { Route as ClientsIdImport } from './routes/clients.$id'
|
||||||
|
import { Route as PasswordRecoveryIndexImport } from './routes/password.recovery.index'
|
||||||
import { Route as PasswordChangeIndexImport } from './routes/password.change.index'
|
import { Route as PasswordChangeIndexImport } from './routes/password.change.index'
|
||||||
import { Route as AccountSessionsIndexImport } from './routes/_account.sessions.index'
|
import { Route as AccountSessionsIndexImport } from './routes/_account.sessions.index'
|
||||||
import { Route as PasswordChangeSuccessImport } from './routes/password.change.success'
|
import { Route as PasswordChangeSuccessImport } from './routes/password.change.success'
|
||||||
@@ -50,6 +51,13 @@ const ClientsIdRoute = ClientsIdImport.update({
|
|||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
|
const PasswordRecoveryIndexRoute = PasswordRecoveryIndexImport.update({
|
||||||
|
path: '/password/recovery/',
|
||||||
|
getParentRoute: () => rootRoute,
|
||||||
|
} as any).lazy(() =>
|
||||||
|
import('./routes/password.recovery.index.lazy').then((d) => d.Route),
|
||||||
|
)
|
||||||
|
|
||||||
const PasswordChangeIndexRoute = PasswordChangeIndexImport.update({
|
const PasswordChangeIndexRoute = PasswordChangeIndexImport.update({
|
||||||
path: '/password/change/',
|
path: '/password/change/',
|
||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
@@ -163,6 +171,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof PasswordChangeIndexImport
|
preLoaderRoute: typeof PasswordChangeIndexImport
|
||||||
parentRoute: typeof rootRoute
|
parentRoute: typeof rootRoute
|
||||||
}
|
}
|
||||||
|
'/password/recovery/': {
|
||||||
|
id: '/password/recovery/'
|
||||||
|
path: '/password/recovery'
|
||||||
|
fullPath: '/password/recovery'
|
||||||
|
preLoaderRoute: typeof PasswordRecoveryIndexImport
|
||||||
|
parentRoute: typeof rootRoute
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,6 +196,7 @@ export const routeTree = rootRoute.addChildren({
|
|||||||
EmailsIdVerifyRoute,
|
EmailsIdVerifyRoute,
|
||||||
PasswordChangeSuccessRoute,
|
PasswordChangeSuccessRoute,
|
||||||
PasswordChangeIndexRoute,
|
PasswordChangeIndexRoute,
|
||||||
|
PasswordRecoveryIndexRoute,
|
||||||
})
|
})
|
||||||
|
|
||||||
/* prettier-ignore-end */
|
/* prettier-ignore-end */
|
||||||
@@ -197,7 +213,8 @@ export const routeTree = rootRoute.addChildren({
|
|||||||
"/devices/$",
|
"/devices/$",
|
||||||
"/emails/$id/verify",
|
"/emails/$id/verify",
|
||||||
"/password/change/success",
|
"/password/change/success",
|
||||||
"/password/change/"
|
"/password/change/",
|
||||||
|
"/password/recovery/"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"/_account": {
|
"/_account": {
|
||||||
@@ -242,6 +259,9 @@ export const routeTree = rootRoute.addChildren({
|
|||||||
},
|
},
|
||||||
"/password/change/": {
|
"/password/change/": {
|
||||||
"filePath": "password.change.index.tsx"
|
"filePath": "password.change.index.tsx"
|
||||||
|
},
|
||||||
|
"/password/recovery/": {
|
||||||
|
"filePath": "password.recovery.index.tsx"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
155
frontend/src/routes/password.recovery.index.lazy.tsx
Normal file
155
frontend/src/routes/password.recovery.index.lazy.tsx
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
// Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import {
|
||||||
|
createLazyFileRoute,
|
||||||
|
useRouter,
|
||||||
|
useSearch,
|
||||||
|
} from "@tanstack/react-router";
|
||||||
|
import IconLockSolid from "@vector-im/compound-design-tokens/assets/web/icons/lock-solid";
|
||||||
|
import { Alert, Form } from "@vector-im/compound-web";
|
||||||
|
import { FormEvent } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useMutation, useQuery } from "urql";
|
||||||
|
|
||||||
|
import BlockList from "../components/BlockList";
|
||||||
|
import Layout from "../components/Layout";
|
||||||
|
import LoadingSpinner from "../components/LoadingSpinner";
|
||||||
|
import PageHeading from "../components/PageHeading";
|
||||||
|
import PasswordCreationDoubleInput from "../components/PasswordCreationDoubleInput";
|
||||||
|
import { graphql } from "../gql";
|
||||||
|
import { SetPasswordStatus } from "../gql/graphql";
|
||||||
|
import { translateSetPasswordError } from "../i18n/password_changes";
|
||||||
|
|
||||||
|
const QUERY = graphql(/* GraphQL */ `
|
||||||
|
query PasswordRecoveryQuery {
|
||||||
|
siteConfig {
|
||||||
|
id
|
||||||
|
...PasswordCreationDoubleInput_siteConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
const RECOVER_PASSWORD_MUTATION = graphql(/* GraphQL */ `
|
||||||
|
mutation RecoverPassword($ticket: String!, $newPassword: String!) {
|
||||||
|
setPasswordByRecovery(
|
||||||
|
input: { ticket: $ticket, newPassword: $newPassword }
|
||||||
|
) {
|
||||||
|
status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
export const Route = createLazyFileRoute("/password/recovery/")({
|
||||||
|
component: RecoverPassword,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RecoverPassword(): React.ReactNode {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { ticket } = useSearch({
|
||||||
|
from: "/password/recovery/",
|
||||||
|
});
|
||||||
|
const [queryResult] = useQuery({ query: QUERY });
|
||||||
|
const router = useRouter();
|
||||||
|
if (queryResult.error) throw queryResult.error;
|
||||||
|
const siteConfig = queryResult.data?.siteConfig;
|
||||||
|
if (!siteConfig) throw Error(); // This should never happen
|
||||||
|
|
||||||
|
const [result, changePassword] = useMutation(RECOVER_PASSWORD_MUTATION);
|
||||||
|
|
||||||
|
const onSubmit = async (event: FormEvent<HTMLFormElement>): Promise<void> => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const formData = new FormData(event.currentTarget);
|
||||||
|
|
||||||
|
const newPassword = formData.get("new_password") as string;
|
||||||
|
const newPasswordAgain = formData.get("new_password_again") as string;
|
||||||
|
|
||||||
|
if (newPassword !== newPasswordAgain) {
|
||||||
|
throw new Error("passwords mismatch; this should be checked by the form");
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await changePassword({ ticket, newPassword });
|
||||||
|
|
||||||
|
if (
|
||||||
|
response.data?.setPasswordByRecovery.status === SetPasswordStatus.Allowed
|
||||||
|
) {
|
||||||
|
// Redirect to the application root using a full page load
|
||||||
|
// The MAS backend will then redirect to the login page
|
||||||
|
// Unfortunately this won't work in dev mode (`npm run dev`)
|
||||||
|
// as the backend isn't involved there.
|
||||||
|
const location = router.buildLocation({ to: "/" });
|
||||||
|
window.location.href = location.href;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const unhandleableError = result.error !== undefined;
|
||||||
|
|
||||||
|
const errorMsg: string | undefined = translateSetPasswordError(
|
||||||
|
t,
|
||||||
|
result.data?.setPasswordByRecovery.status,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<BlockList>
|
||||||
|
<PageHeading
|
||||||
|
Icon={IconLockSolid}
|
||||||
|
title={t("frontend.password_reset.title")}
|
||||||
|
subtitle={t("frontend.password_change.subtitle")}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Form.Root onSubmit={onSubmit} method="POST">
|
||||||
|
{/*
|
||||||
|
In normal operation, the submit event should be `preventDefault()`ed.
|
||||||
|
method = POST just prevents sending passwords in the query string,
|
||||||
|
which could be logged, if for some reason the event handler fails.
|
||||||
|
*/}
|
||||||
|
{unhandleableError && (
|
||||||
|
<Alert
|
||||||
|
type="critical"
|
||||||
|
title={t("frontend.password_change.failure.title")}
|
||||||
|
>
|
||||||
|
{t("frontend.password_change.failure.description.unspecified")}
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{errorMsg !== undefined && (
|
||||||
|
<Alert
|
||||||
|
type="critical"
|
||||||
|
title={t("frontend.password_change.failure.title")}
|
||||||
|
>
|
||||||
|
{errorMsg}
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<PasswordCreationDoubleInput
|
||||||
|
siteConfig={siteConfig}
|
||||||
|
forceShowNewPasswordInvalid={
|
||||||
|
(result.data &&
|
||||||
|
result.data.setPasswordByRecovery.status ==
|
||||||
|
SetPasswordStatus.InvalidNewPassword) ||
|
||||||
|
false
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Form.Submit kind="primary" disabled={result.fetching}>
|
||||||
|
{!!result.fetching && <LoadingSpinner inline />}
|
||||||
|
{t("action.save_and_continue")}
|
||||||
|
</Form.Submit>
|
||||||
|
</Form.Root>
|
||||||
|
</BlockList>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
}
|
41
frontend/src/routes/password.recovery.index.tsx
Normal file
41
frontend/src/routes/password.recovery.index.tsx
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
// Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
|
|
||||||
|
import { graphql } from "../gql";
|
||||||
|
|
||||||
|
const QUERY = graphql(/* GraphQL */ `
|
||||||
|
query PasswordRecoveryQuery {
|
||||||
|
siteConfig {
|
||||||
|
id
|
||||||
|
...PasswordCreationDoubleInput_siteConfig
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
export const Route = createFileRoute("/password/recovery/")({
|
||||||
|
validateSearch: (search) =>
|
||||||
|
search as {
|
||||||
|
ticket: string;
|
||||||
|
},
|
||||||
|
async loader({ context, abortController: { signal } }) {
|
||||||
|
const queryResult = await context.client.query(
|
||||||
|
QUERY,
|
||||||
|
{},
|
||||||
|
{ fetchOptions: { signal } },
|
||||||
|
);
|
||||||
|
if (queryResult.error) throw queryResult.error;
|
||||||
|
},
|
||||||
|
});
|
Reference in New Issue
Block a user