mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-03 06:03:21 +03:00
fix(server): change password with token should be public (#7855)
This commit is contained in:
parent
7afba6b8b5
commit
0ba516866f
@ -16,6 +16,7 @@ import {
|
|||||||
EmailTokenNotFound,
|
EmailTokenNotFound,
|
||||||
EmailVerificationRequired,
|
EmailVerificationRequired,
|
||||||
InvalidEmailToken,
|
InvalidEmailToken,
|
||||||
|
LinkExpired,
|
||||||
SameEmailProvided,
|
SameEmailProvided,
|
||||||
SkipThrottle,
|
SkipThrottle,
|
||||||
Throttle,
|
Throttle,
|
||||||
@ -89,12 +90,17 @@ export class AuthResolver {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mutation(() => UserType)
|
@Public()
|
||||||
|
@Mutation(() => Boolean)
|
||||||
async changePassword(
|
async changePassword(
|
||||||
@CurrentUser() user: CurrentUser,
|
|
||||||
@Args('token') token: string,
|
@Args('token') token: string,
|
||||||
@Args('newPassword') newPassword: string
|
@Args('newPassword') newPassword: string,
|
||||||
|
@Args('userId', { type: () => String, nullable: true }) userId?: string
|
||||||
) {
|
) {
|
||||||
|
if (!userId) {
|
||||||
|
throw new LinkExpired();
|
||||||
|
}
|
||||||
|
|
||||||
const config = await this.config.runtime.fetchAll({
|
const config = await this.config.runtime.fetchAll({
|
||||||
'auth/password.max': true,
|
'auth/password.max': true,
|
||||||
'auth/password.min': true,
|
'auth/password.min': true,
|
||||||
@ -108,7 +114,7 @@ export class AuthResolver {
|
|||||||
TokenType.ChangePassword,
|
TokenType.ChangePassword,
|
||||||
token,
|
token,
|
||||||
{
|
{
|
||||||
credential: user.id,
|
credential: userId,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -116,10 +122,10 @@ export class AuthResolver {
|
|||||||
throw new InvalidEmailToken();
|
throw new InvalidEmailToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.auth.changePassword(user.id, newPassword);
|
await this.auth.changePassword(userId, newPassword);
|
||||||
await this.auth.revokeUserSessions(user.id);
|
await this.auth.revokeUserSessions(userId);
|
||||||
|
|
||||||
return user;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mutation(() => UserType)
|
@Mutation(() => UserType)
|
||||||
@ -163,7 +169,7 @@ export class AuthResolver {
|
|||||||
user.id
|
user.id
|
||||||
);
|
);
|
||||||
|
|
||||||
const url = this.url.link(callbackUrl, { token });
|
const url = this.url.link(callbackUrl, { userId: user.id, token });
|
||||||
|
|
||||||
const res = await this.auth.sendChangePasswordEmail(user.email, url);
|
const res = await this.auth.sendChangePasswordEmail(user.email, url);
|
||||||
|
|
||||||
@ -176,19 +182,7 @@ export class AuthResolver {
|
|||||||
@Args('callbackUrl') callbackUrl: string,
|
@Args('callbackUrl') callbackUrl: string,
|
||||||
@Args('email', { nullable: true }) _email?: string
|
@Args('email', { nullable: true }) _email?: string
|
||||||
) {
|
) {
|
||||||
if (!user.emailVerified) {
|
return this.sendChangePasswordEmail(user, callbackUrl);
|
||||||
throw new EmailVerificationRequired();
|
|
||||||
}
|
|
||||||
|
|
||||||
const token = await this.token.createToken(
|
|
||||||
TokenType.ChangePassword,
|
|
||||||
user.id
|
|
||||||
);
|
|
||||||
|
|
||||||
const url = this.url.link(callbackUrl, { token });
|
|
||||||
|
|
||||||
const res = await this.auth.sendSetPasswordEmail(user.email, url);
|
|
||||||
return !res.rejected.length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The change email step is:
|
// The change email step is:
|
||||||
@ -305,6 +299,7 @@ export class AuthResolver {
|
|||||||
TokenType.ChangePassword,
|
TokenType.ChangePassword,
|
||||||
userId
|
userId
|
||||||
);
|
);
|
||||||
return this.url.link(callbackUrl, { token });
|
|
||||||
|
return this.url.link(callbackUrl, { userId, token });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,6 +279,10 @@ export const USER_FRIENDLY_ERRORS = {
|
|||||||
type: 'invalid_input',
|
type: 'invalid_input',
|
||||||
message: 'An invalid email token provided.',
|
message: 'An invalid email token provided.',
|
||||||
},
|
},
|
||||||
|
link_expired: {
|
||||||
|
type: 'bad_request',
|
||||||
|
message: 'The link has expired.',
|
||||||
|
},
|
||||||
|
|
||||||
// Authentication & Permission Errors
|
// Authentication & Permission Errors
|
||||||
authentication_required: {
|
authentication_required: {
|
||||||
|
@ -137,6 +137,12 @@ export class InvalidEmailToken extends UserFriendlyError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class LinkExpired extends UserFriendlyError {
|
||||||
|
constructor(message?: string) {
|
||||||
|
super('bad_request', 'link_expired', message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class AuthenticationRequired extends UserFriendlyError {
|
export class AuthenticationRequired extends UserFriendlyError {
|
||||||
constructor(message?: string) {
|
constructor(message?: string) {
|
||||||
super('authentication_required', 'authentication_required', message);
|
super('authentication_required', 'authentication_required', message);
|
||||||
@ -520,6 +526,7 @@ export enum ErrorNames {
|
|||||||
SIGN_UP_FORBIDDEN,
|
SIGN_UP_FORBIDDEN,
|
||||||
EMAIL_TOKEN_NOT_FOUND,
|
EMAIL_TOKEN_NOT_FOUND,
|
||||||
INVALID_EMAIL_TOKEN,
|
INVALID_EMAIL_TOKEN,
|
||||||
|
LINK_EXPIRED,
|
||||||
AUTHENTICATION_REQUIRED,
|
AUTHENTICATION_REQUIRED,
|
||||||
ACTION_FORBIDDEN,
|
ACTION_FORBIDDEN,
|
||||||
ACCESS_DENIED,
|
ACCESS_DENIED,
|
||||||
|
@ -235,6 +235,7 @@ enum ErrorNames {
|
|||||||
INVALID_OAUTH_CALLBACK_STATE
|
INVALID_OAUTH_CALLBACK_STATE
|
||||||
INVALID_PASSWORD_LENGTH
|
INVALID_PASSWORD_LENGTH
|
||||||
INVALID_RUNTIME_CONFIG_TYPE
|
INVALID_RUNTIME_CONFIG_TYPE
|
||||||
|
LINK_EXPIRED
|
||||||
MAILER_SERVICE_IS_NOT_CONFIGURED
|
MAILER_SERVICE_IS_NOT_CONFIGURED
|
||||||
MEMBER_QUOTA_EXCEEDED
|
MEMBER_QUOTA_EXCEEDED
|
||||||
MISSING_OAUTH_QUERY_PARAMETER
|
MISSING_OAUTH_QUERY_PARAMETER
|
||||||
@ -409,7 +410,7 @@ type Mutation {
|
|||||||
addWorkspaceFeature(feature: FeatureType!, workspaceId: String!): Int!
|
addWorkspaceFeature(feature: FeatureType!, workspaceId: String!): Int!
|
||||||
cancelSubscription(idempotencyKey: String!, plan: SubscriptionPlan = Pro): UserSubscription!
|
cancelSubscription(idempotencyKey: String!, plan: SubscriptionPlan = Pro): UserSubscription!
|
||||||
changeEmail(email: String!, token: String!): UserType!
|
changeEmail(email: String!, token: String!): UserType!
|
||||||
changePassword(newPassword: String!, token: String!): UserType!
|
changePassword(newPassword: String!, token: String!, userId: String): Boolean!
|
||||||
|
|
||||||
"""Cleanup sessions"""
|
"""Cleanup sessions"""
|
||||||
cleanupCopilotSession(options: DeleteSessionInput!): [String!]!
|
cleanupCopilotSession(options: DeleteSessionInput!): [String!]!
|
||||||
|
@ -132,13 +132,14 @@ test('set and change password', async t => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const newPassword = randomBytes(16).toString('hex');
|
const newPassword = randomBytes(16).toString('hex');
|
||||||
const userId = await changePassword(
|
const success = await changePassword(
|
||||||
app,
|
app,
|
||||||
u1.token.token,
|
u1.id,
|
||||||
setPasswordToken as string,
|
setPasswordToken as string,
|
||||||
newPassword
|
newPassword
|
||||||
);
|
);
|
||||||
t.is(u1.id, userId, 'failed to set password');
|
|
||||||
|
t.true(success, 'failed to change password');
|
||||||
|
|
||||||
const ret = auth.signIn(u1Email, newPassword);
|
const ret = auth.signIn(u1Email, newPassword);
|
||||||
t.notThrowsAsync(ret, 'failed to check password');
|
t.notThrowsAsync(ret, 'failed to check password');
|
||||||
@ -201,7 +202,7 @@ test('should revoke token after change user identify', async t => {
|
|||||||
await sendSetPasswordEmail(app, u3.token.token, u3Email, 'affine.pro');
|
await sendSetPasswordEmail(app, u3.token.token, u3Email, 'affine.pro');
|
||||||
const token = await getTokenFromLatestMailMessage();
|
const token = await getTokenFromLatestMailMessage();
|
||||||
const newPassword = randomBytes(16).toString('hex');
|
const newPassword = randomBytes(16).toString('hex');
|
||||||
await changePassword(app, u3.token.token, token as string, newPassword);
|
await changePassword(app, u3.id, token as string, newPassword);
|
||||||
|
|
||||||
const user = await currentUser(app, u3.token.token);
|
const user = await currentUser(app, u3.token.token);
|
||||||
t.is(user, null, 'token should be revoked');
|
t.is(user, null, 'token should be revoked');
|
||||||
|
@ -129,26 +129,23 @@ export async function sendSetPasswordEmail(
|
|||||||
|
|
||||||
export async function changePassword(
|
export async function changePassword(
|
||||||
app: INestApplication,
|
app: INestApplication,
|
||||||
userToken: string,
|
userId: string,
|
||||||
token: string,
|
token: string,
|
||||||
password: string
|
password: string
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const res = await request(app.getHttpServer())
|
const res = await request(app.getHttpServer())
|
||||||
.post(gql)
|
.post(gql)
|
||||||
.auth(userToken, { type: 'bearer' })
|
|
||||||
.set({ 'x-request-id': 'test', 'x-operation-name': 'test' })
|
.set({ 'x-request-id': 'test', 'x-operation-name': 'test' })
|
||||||
.send({
|
.send({
|
||||||
query: `
|
query: `
|
||||||
mutation changePassword($token: String!, $password: String!) {
|
mutation changePassword($token: String!, $userId: String!, $password: String!) {
|
||||||
changePassword(token: $token, newPassword: $password) {
|
changePassword(token: $token, userId: $userId, newPassword: $password)
|
||||||
id
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
variables: { token, password },
|
variables: { token, password, userId },
|
||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
return res.body.data.changePassword.id;
|
return res.body.data.changePassword;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function sendVerifyChangeEmail(
|
export async function sendVerifyChangeEmail(
|
||||||
|
@ -7,19 +7,12 @@ import { Button } from '../../ui/button';
|
|||||||
import { notify } from '../../ui/notification';
|
import { notify } from '../../ui/notification';
|
||||||
import { AuthPageContainer } from './auth-page-container';
|
import { AuthPageContainer } from './auth-page-container';
|
||||||
import { SetPassword } from './set-password';
|
import { SetPassword } from './set-password';
|
||||||
import type { User } from './type';
|
|
||||||
|
|
||||||
export const ChangePasswordPage: FC<{
|
export const ChangePasswordPage: FC<{
|
||||||
user: User;
|
|
||||||
passwordLimits: PasswordLimitsFragment;
|
passwordLimits: PasswordLimitsFragment;
|
||||||
onSetPassword: (password: string) => Promise<void>;
|
onSetPassword: (password: string) => Promise<void>;
|
||||||
onOpenAffine: () => void;
|
onOpenAffine: () => void;
|
||||||
}> = ({
|
}> = ({ passwordLimits, onSetPassword: propsOnSetPassword, onOpenAffine }) => {
|
||||||
user: { email },
|
|
||||||
passwordLimits,
|
|
||||||
onSetPassword: propsOnSetPassword,
|
|
||||||
onOpenAffine,
|
|
||||||
}) => {
|
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const [hasSetUp, setHasSetUp] = useState(false);
|
const [hasSetUp, setHasSetUp] = useState(false);
|
||||||
|
|
||||||
@ -45,17 +38,12 @@ export const ChangePasswordPage: FC<{
|
|||||||
: t['com.affine.auth.reset.password.page.title']()
|
: t['com.affine.auth.reset.password.page.title']()
|
||||||
}
|
}
|
||||||
subtitle={
|
subtitle={
|
||||||
hasSetUp ? (
|
hasSetUp
|
||||||
t['com.affine.auth.sent.reset.password.success.message']()
|
? t['com.affine.auth.sent.reset.password.success.message']()
|
||||||
) : (
|
: t['com.affine.auth.page.sent.email.subtitle']({
|
||||||
<>
|
|
||||||
{t['com.affine.auth.page.sent.email.subtitle']({
|
|
||||||
min: String(passwordLimits.minLength),
|
min: String(passwordLimits.minLength),
|
||||||
max: String(passwordLimits.maxLength),
|
max: String(passwordLimits.maxLength),
|
||||||
})}
|
})
|
||||||
<a href={`mailto:${email}`}>{email}</a>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{hasSetUp ? (
|
{hasSetUp ? (
|
||||||
|
@ -7,19 +7,12 @@ import { Button } from '../../ui/button';
|
|||||||
import { notify } from '../../ui/notification';
|
import { notify } from '../../ui/notification';
|
||||||
import { AuthPageContainer } from './auth-page-container';
|
import { AuthPageContainer } from './auth-page-container';
|
||||||
import { SetPassword } from './set-password';
|
import { SetPassword } from './set-password';
|
||||||
import type { User } from './type';
|
|
||||||
|
|
||||||
export const SetPasswordPage: FC<{
|
export const SetPasswordPage: FC<{
|
||||||
user: User;
|
|
||||||
passwordLimits: PasswordLimitsFragment;
|
passwordLimits: PasswordLimitsFragment;
|
||||||
onSetPassword: (password: string) => Promise<void>;
|
onSetPassword: (password: string) => Promise<void>;
|
||||||
onOpenAffine: () => void;
|
onOpenAffine: () => void;
|
||||||
}> = ({
|
}> = ({ passwordLimits, onSetPassword: propsOnSetPassword, onOpenAffine }) => {
|
||||||
user: { email },
|
|
||||||
passwordLimits,
|
|
||||||
onSetPassword: propsOnSetPassword,
|
|
||||||
onOpenAffine,
|
|
||||||
}) => {
|
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const [hasSetUp, setHasSetUp] = useState(false);
|
const [hasSetUp, setHasSetUp] = useState(false);
|
||||||
|
|
||||||
@ -45,17 +38,12 @@ export const SetPasswordPage: FC<{
|
|||||||
: t['com.affine.auth.set.password.page.title']()
|
: t['com.affine.auth.set.password.page.title']()
|
||||||
}
|
}
|
||||||
subtitle={
|
subtitle={
|
||||||
hasSetUp ? (
|
hasSetUp
|
||||||
t['com.affine.auth.sent.set.password.success.message']()
|
? t['com.affine.auth.sent.set.password.success.message']()
|
||||||
) : (
|
: t['com.affine.auth.page.sent.email.subtitle']({
|
||||||
<>
|
|
||||||
{t['com.affine.auth.page.sent.email.subtitle']({
|
|
||||||
min: String(passwordLimits.minLength),
|
min: String(passwordLimits.minLength),
|
||||||
max: String(passwordLimits.maxLength),
|
max: String(passwordLimits.maxLength),
|
||||||
})}
|
})
|
||||||
<a href={`mailto:${email}`}>{email}</a>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{hasSetUp ? (
|
{hasSetUp ? (
|
||||||
|
@ -17,8 +17,7 @@ import {
|
|||||||
} from '@affine/graphql';
|
} from '@affine/graphql';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import { useLiveData, useService } from '@toeverything/infra';
|
import { useLiveData, useService } from '@toeverything/infra';
|
||||||
import type { ReactElement } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { useCallback, useEffect } from 'react';
|
|
||||||
import type { LoaderFunction } from 'react-router-dom';
|
import type { LoaderFunction } from 'react-router-dom';
|
||||||
import { redirect, useParams, useSearchParams } from 'react-router-dom';
|
import { redirect, useParams, useSearchParams } from 'react-router-dom';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
@ -39,7 +38,7 @@ const authTypeSchema = z.enum([
|
|||||||
'verify-email',
|
'verify-email',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const AuthPage = (): ReactElement | null => {
|
export const Component = () => {
|
||||||
const authService = useService(AuthService);
|
const authService = useService(AuthService);
|
||||||
const account = useLiveData(authService.session.account$);
|
const account = useLiveData(authService.session.account$);
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
@ -89,6 +88,7 @@ export const AuthPage = (): ReactElement | null => {
|
|||||||
async (password: string) => {
|
async (password: string) => {
|
||||||
await changePassword({
|
await changePassword({
|
||||||
token: searchParams.get('token') || '',
|
token: searchParams.get('token') || '',
|
||||||
|
userId: searchParams.get('userId') || '',
|
||||||
newPassword: password,
|
newPassword: password,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -98,22 +98,26 @@ export const AuthPage = (): ReactElement | null => {
|
|||||||
jumpToIndex(RouteLogic.REPLACE);
|
jumpToIndex(RouteLogic.REPLACE);
|
||||||
}, [jumpToIndex]);
|
}, [jumpToIndex]);
|
||||||
|
|
||||||
if (!passwordLimits || !account) {
|
if (!passwordLimits) {
|
||||||
// TODO(@eyhn): loading UI
|
// TODO(@eyhn): loading UI
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (authType) {
|
switch (authType) {
|
||||||
case 'onboarding':
|
case 'onboarding':
|
||||||
return <OnboardingPage user={account} onOpenAffine={onOpenAffine} />;
|
return (
|
||||||
|
account && <OnboardingPage user={account} onOpenAffine={onOpenAffine} />
|
||||||
|
);
|
||||||
case 'signUp': {
|
case 'signUp': {
|
||||||
return (
|
return (
|
||||||
<SignUpPage
|
account && (
|
||||||
user={account}
|
<SignUpPage
|
||||||
passwordLimits={passwordLimits}
|
user={account}
|
||||||
onSetPassword={onSetPassword}
|
passwordLimits={passwordLimits}
|
||||||
onOpenAffine={onOpenAffine}
|
onSetPassword={onSetPassword}
|
||||||
/>
|
onOpenAffine={onOpenAffine}
|
||||||
|
/>
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case 'signIn': {
|
case 'signIn': {
|
||||||
@ -122,7 +126,6 @@ export const AuthPage = (): ReactElement | null => {
|
|||||||
case 'changePassword': {
|
case 'changePassword': {
|
||||||
return (
|
return (
|
||||||
<ChangePasswordPage
|
<ChangePasswordPage
|
||||||
user={account}
|
|
||||||
passwordLimits={passwordLimits}
|
passwordLimits={passwordLimits}
|
||||||
onSetPassword={onSetPassword}
|
onSetPassword={onSetPassword}
|
||||||
onOpenAffine={onOpenAffine}
|
onOpenAffine={onOpenAffine}
|
||||||
@ -132,7 +135,6 @@ export const AuthPage = (): ReactElement | null => {
|
|||||||
case 'setPassword': {
|
case 'setPassword': {
|
||||||
return (
|
return (
|
||||||
<SetPasswordPage
|
<SetPasswordPage
|
||||||
user={account}
|
|
||||||
passwordLimits={passwordLimits}
|
passwordLimits={passwordLimits}
|
||||||
onSetPassword={onSetPassword}
|
onSetPassword={onSetPassword}
|
||||||
onOpenAffine={onOpenAffine}
|
onOpenAffine={onOpenAffine}
|
||||||
@ -198,25 +200,3 @@ export const loader: LoaderFunction = async args => {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Component = () => {
|
|
||||||
const authService = useService(AuthService);
|
|
||||||
const isRevalidating = useLiveData(authService.session.isRevalidating$);
|
|
||||||
const loginStatus = useLiveData(authService.session.status$);
|
|
||||||
const { jumpToExpired } = useNavigateHelper();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
authService.session.revalidate();
|
|
||||||
}, [authService]);
|
|
||||||
|
|
||||||
if (loginStatus === 'unauthenticated' && !isRevalidating) {
|
|
||||||
jumpToExpired(RouteLogic.REPLACE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loginStatus === 'authenticated') {
|
|
||||||
return <AuthPage />;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(@eyhn): loading UI
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
mutation changePassword($token: String!, $newPassword: String!) {
|
mutation changePassword(
|
||||||
changePassword(token: $token, newPassword: $newPassword) {
|
$token: String!
|
||||||
id
|
$userId: String!
|
||||||
}
|
$newPassword: String!
|
||||||
|
) {
|
||||||
|
changePassword(token: $token, userId: $userId, newPassword: $newPassword)
|
||||||
}
|
}
|
||||||
|
@ -121,10 +121,8 @@ export const changePasswordMutation = {
|
|||||||
definitionName: 'changePassword',
|
definitionName: 'changePassword',
|
||||||
containsFile: false,
|
containsFile: false,
|
||||||
query: `
|
query: `
|
||||||
mutation changePassword($token: String!, $newPassword: String!) {
|
mutation changePassword($token: String!, $userId: String!, $newPassword: String!) {
|
||||||
changePassword(token: $token, newPassword: $newPassword) {
|
changePassword(token: $token, userId: $userId, newPassword: $newPassword)
|
||||||
id
|
|
||||||
}
|
|
||||||
}`,
|
}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -306,6 +306,7 @@ export enum ErrorNames {
|
|||||||
INVALID_OAUTH_CALLBACK_STATE = 'INVALID_OAUTH_CALLBACK_STATE',
|
INVALID_OAUTH_CALLBACK_STATE = 'INVALID_OAUTH_CALLBACK_STATE',
|
||||||
INVALID_PASSWORD_LENGTH = 'INVALID_PASSWORD_LENGTH',
|
INVALID_PASSWORD_LENGTH = 'INVALID_PASSWORD_LENGTH',
|
||||||
INVALID_RUNTIME_CONFIG_TYPE = 'INVALID_RUNTIME_CONFIG_TYPE',
|
INVALID_RUNTIME_CONFIG_TYPE = 'INVALID_RUNTIME_CONFIG_TYPE',
|
||||||
|
LINK_EXPIRED = 'LINK_EXPIRED',
|
||||||
MAILER_SERVICE_IS_NOT_CONFIGURED = 'MAILER_SERVICE_IS_NOT_CONFIGURED',
|
MAILER_SERVICE_IS_NOT_CONFIGURED = 'MAILER_SERVICE_IS_NOT_CONFIGURED',
|
||||||
MEMBER_QUOTA_EXCEEDED = 'MEMBER_QUOTA_EXCEEDED',
|
MEMBER_QUOTA_EXCEEDED = 'MEMBER_QUOTA_EXCEEDED',
|
||||||
MISSING_OAUTH_QUERY_PARAMETER = 'MISSING_OAUTH_QUERY_PARAMETER',
|
MISSING_OAUTH_QUERY_PARAMETER = 'MISSING_OAUTH_QUERY_PARAMETER',
|
||||||
@ -467,7 +468,7 @@ export interface Mutation {
|
|||||||
addWorkspaceFeature: Scalars['Int']['output'];
|
addWorkspaceFeature: Scalars['Int']['output'];
|
||||||
cancelSubscription: UserSubscription;
|
cancelSubscription: UserSubscription;
|
||||||
changeEmail: UserType;
|
changeEmail: UserType;
|
||||||
changePassword: UserType;
|
changePassword: Scalars['Boolean']['output'];
|
||||||
/** Cleanup sessions */
|
/** Cleanup sessions */
|
||||||
cleanupCopilotSession: Array<Scalars['String']['output']>;
|
cleanupCopilotSession: Array<Scalars['String']['output']>;
|
||||||
/** Create change password url */
|
/** Create change password url */
|
||||||
@ -557,6 +558,7 @@ export interface MutationChangeEmailArgs {
|
|||||||
export interface MutationChangePasswordArgs {
|
export interface MutationChangePasswordArgs {
|
||||||
newPassword: Scalars['String']['input'];
|
newPassword: Scalars['String']['input'];
|
||||||
token: Scalars['String']['input'];
|
token: Scalars['String']['input'];
|
||||||
|
userId: InputMaybe<Scalars['String']['input']>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MutationCleanupCopilotSessionArgs {
|
export interface MutationCleanupCopilotSessionArgs {
|
||||||
@ -1321,12 +1323,13 @@ export type CreateChangePasswordUrlMutation = {
|
|||||||
|
|
||||||
export type ChangePasswordMutationVariables = Exact<{
|
export type ChangePasswordMutationVariables = Exact<{
|
||||||
token: Scalars['String']['input'];
|
token: Scalars['String']['input'];
|
||||||
|
userId: Scalars['String']['input'];
|
||||||
newPassword: Scalars['String']['input'];
|
newPassword: Scalars['String']['input'];
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export type ChangePasswordMutation = {
|
export type ChangePasswordMutation = {
|
||||||
__typename?: 'Mutation';
|
__typename?: 'Mutation';
|
||||||
changePassword: { __typename?: 'UserType'; id: string };
|
changePassword: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CopilotQuotaQueryVariables = Exact<{ [key: string]: never }>;
|
export type CopilotQuotaQueryVariables = Exact<{ [key: string]: never }>;
|
||||||
|
Loading…
Reference in New Issue
Block a user