mirror of
https://tangled.org/tranquil.farm/tranquil-pds
synced 2026-09-06 18:26:56 +00:00
refactor(frontend): simplify API client and delete obsolete auth routes
This commit is contained in:
+12
-634
@@ -441,9 +441,13 @@ export const api = {
|
||||
params: {
|
||||
did: Did;
|
||||
handle: Handle;
|
||||
email: EmailAddress;
|
||||
email?: EmailAddress;
|
||||
password: string;
|
||||
inviteCode?: string;
|
||||
verificationChannel?: string;
|
||||
discordUsername?: string;
|
||||
telegramUsername?: string;
|
||||
signalUsername?: string;
|
||||
},
|
||||
): Promise<Session> {
|
||||
const url = `${API_BASE}/com.atproto.server.createAccount`;
|
||||
@@ -459,6 +463,10 @@ export const api = {
|
||||
email: params.email,
|
||||
password: params.password,
|
||||
inviteCode: params.inviteCode,
|
||||
verificationChannel: params.verificationChannel,
|
||||
discordUsername: params.discordUsername,
|
||||
telegramUsername: params.telegramUsername,
|
||||
signalUsername: params.signalUsername,
|
||||
}),
|
||||
});
|
||||
const data = await response.json();
|
||||
@@ -1231,11 +1239,12 @@ export const api = {
|
||||
},
|
||||
|
||||
resendMigrationVerification(
|
||||
email: EmailAddress,
|
||||
channel: string,
|
||||
identifier: string,
|
||||
): Promise<ResendMigrationVerificationResponse> {
|
||||
return xrpc("com.atproto.server.resendMigrationVerification", {
|
||||
method: "POST",
|
||||
body: { email },
|
||||
body: { channel, identifier },
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1509,634 +1518,3 @@ export const api = {
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
export const typedApi = {
|
||||
createSession(
|
||||
identifier: string,
|
||||
password: string,
|
||||
): Promise<Result<Session, ApiError>> {
|
||||
return xrpcResult<Session>("com.atproto.server.createSession", {
|
||||
method: "POST",
|
||||
body: { identifier, password },
|
||||
}).then((r) => r.ok ? ok(castSession(r.value)) : r);
|
||||
},
|
||||
|
||||
getSession(token: AccessToken): Promise<Result<Session, ApiError>> {
|
||||
return xrpcResult<Session>("com.atproto.server.getSession", { token })
|
||||
.then((r) => r.ok ? ok(castSession(r.value)) : r);
|
||||
},
|
||||
|
||||
refreshSession(refreshJwt: RefreshToken): Promise<Result<Session, ApiError>> {
|
||||
return xrpcResult<Session>("com.atproto.server.refreshSession", {
|
||||
method: "POST",
|
||||
token: refreshJwt,
|
||||
}).then((r) => r.ok ? ok(castSession(r.value)) : r);
|
||||
},
|
||||
|
||||
describeServer(): Promise<Result<ServerDescription, ApiError>> {
|
||||
return xrpcResult("com.atproto.server.describeServer");
|
||||
},
|
||||
|
||||
listAppPasswords(
|
||||
token: AccessToken,
|
||||
): Promise<Result<{ passwords: AppPassword[] }, ApiError>> {
|
||||
return xrpcResult("com.atproto.server.listAppPasswords", { token });
|
||||
},
|
||||
|
||||
createAppPassword(
|
||||
token: AccessToken,
|
||||
name: string,
|
||||
scopes?: string,
|
||||
): Promise<Result<CreatedAppPassword, ApiError>> {
|
||||
return xrpcResult("com.atproto.server.createAppPassword", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { name, scopes },
|
||||
});
|
||||
},
|
||||
|
||||
revokeAppPassword(
|
||||
token: AccessToken,
|
||||
name: string,
|
||||
): Promise<Result<void, ApiError>> {
|
||||
return xrpcResult<void>("com.atproto.server.revokeAppPassword", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { name },
|
||||
});
|
||||
},
|
||||
|
||||
listSessions(
|
||||
token: AccessToken,
|
||||
): Promise<Result<ListSessionsResponse, ApiError>> {
|
||||
return xrpcResult("_account.listSessions", { token });
|
||||
},
|
||||
|
||||
revokeSession(
|
||||
token: AccessToken,
|
||||
sessionId: string,
|
||||
): Promise<Result<void, ApiError>> {
|
||||
return xrpcResult<void>("_account.revokeSession", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { sessionId },
|
||||
});
|
||||
},
|
||||
|
||||
getTotpStatus(token: AccessToken): Promise<Result<TotpStatus, ApiError>> {
|
||||
return xrpcResult("com.atproto.server.getTotpStatus", { token });
|
||||
},
|
||||
|
||||
createTotpSecret(token: AccessToken): Promise<Result<TotpSecret, ApiError>> {
|
||||
return xrpcResult("com.atproto.server.createTotpSecret", {
|
||||
method: "POST",
|
||||
token,
|
||||
});
|
||||
},
|
||||
|
||||
enableTotp(
|
||||
token: AccessToken,
|
||||
code: string,
|
||||
): Promise<Result<EnableTotpResponse, ApiError>> {
|
||||
return xrpcResult("com.atproto.server.enableTotp", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { code },
|
||||
});
|
||||
},
|
||||
|
||||
disableTotp(
|
||||
token: AccessToken,
|
||||
password: string,
|
||||
code: string,
|
||||
): Promise<Result<SuccessResponse, ApiError>> {
|
||||
return xrpcResult("com.atproto.server.disableTotp", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { password, code },
|
||||
});
|
||||
},
|
||||
|
||||
listPasskeys(
|
||||
token: AccessToken,
|
||||
): Promise<Result<ListPasskeysResponse, ApiError>> {
|
||||
return xrpcResult("com.atproto.server.listPasskeys", { token });
|
||||
},
|
||||
|
||||
deletePasskey(
|
||||
token: AccessToken,
|
||||
id: string,
|
||||
): Promise<Result<void, ApiError>> {
|
||||
return xrpcResult<void>("com.atproto.server.deletePasskey", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { id },
|
||||
});
|
||||
},
|
||||
|
||||
listTrustedDevices(
|
||||
token: AccessToken,
|
||||
): Promise<Result<ListTrustedDevicesResponse, ApiError>> {
|
||||
return xrpcResult("_account.listTrustedDevices", { token });
|
||||
},
|
||||
|
||||
getReauthStatus(token: AccessToken): Promise<Result<ReauthStatus, ApiError>> {
|
||||
return xrpcResult("_account.getReauthStatus", { token });
|
||||
},
|
||||
|
||||
getNotificationPrefs(
|
||||
token: AccessToken,
|
||||
): Promise<Result<NotificationPrefs, ApiError>> {
|
||||
return xrpcResult("_account.getNotificationPrefs", { token });
|
||||
},
|
||||
|
||||
updateHandle(
|
||||
token: AccessToken,
|
||||
handle: Handle,
|
||||
): Promise<Result<void, ApiError>> {
|
||||
return xrpcResult<void>("com.atproto.identity.updateHandle", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { handle },
|
||||
});
|
||||
},
|
||||
|
||||
describeRepo(
|
||||
token: AccessToken,
|
||||
repo: Did,
|
||||
): Promise<Result<RepoDescription, ApiError>> {
|
||||
return xrpcResult("com.atproto.repo.describeRepo", {
|
||||
token,
|
||||
params: { repo },
|
||||
});
|
||||
},
|
||||
|
||||
listRecords(
|
||||
token: AccessToken,
|
||||
repo: Did,
|
||||
collection: Nsid,
|
||||
options?: { limit?: number; cursor?: string; reverse?: boolean },
|
||||
): Promise<Result<ListRecordsResponse, ApiError>> {
|
||||
const params: Record<string, string> = { repo, collection };
|
||||
if (options?.limit) params.limit = String(options.limit);
|
||||
if (options?.cursor) params.cursor = options.cursor;
|
||||
if (options?.reverse) params.reverse = "true";
|
||||
return xrpcResult("com.atproto.repo.listRecords", { token, params });
|
||||
},
|
||||
|
||||
getRecord(
|
||||
token: AccessToken,
|
||||
repo: Did,
|
||||
collection: Nsid,
|
||||
rkey: Rkey,
|
||||
): Promise<Result<RecordResponse, ApiError>> {
|
||||
return xrpcResult("com.atproto.repo.getRecord", {
|
||||
token,
|
||||
params: { repo, collection, rkey },
|
||||
});
|
||||
},
|
||||
|
||||
deleteRecord(
|
||||
token: AccessToken,
|
||||
repo: Did,
|
||||
collection: Nsid,
|
||||
rkey: Rkey,
|
||||
): Promise<Result<void, ApiError>> {
|
||||
return xrpcResult<void>("com.atproto.repo.deleteRecord", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { repo, collection, rkey },
|
||||
});
|
||||
},
|
||||
|
||||
searchAccounts(
|
||||
token: AccessToken,
|
||||
options?: { handle?: string; cursor?: string; limit?: number },
|
||||
): Promise<Result<SearchAccountsResponse, ApiError>> {
|
||||
const params: Record<string, string> = {};
|
||||
if (options?.handle) params.handle = options.handle;
|
||||
if (options?.cursor) params.cursor = options.cursor;
|
||||
if (options?.limit) params.limit = String(options.limit);
|
||||
return xrpcResult("com.atproto.admin.searchAccounts", { token, params });
|
||||
},
|
||||
|
||||
getAccountInfo(
|
||||
token: AccessToken,
|
||||
did: Did,
|
||||
): Promise<Result<AccountInfo, ApiError>> {
|
||||
return xrpcResult("com.atproto.admin.getAccountInfo", {
|
||||
token,
|
||||
params: { did },
|
||||
});
|
||||
},
|
||||
|
||||
getServerStats(token: AccessToken): Promise<Result<ServerStats, ApiError>> {
|
||||
return xrpcResult("_admin.getServerStats", { token });
|
||||
},
|
||||
|
||||
getDidDocument(token: AccessToken): Promise<Result<DidDocument, ApiError>> {
|
||||
return xrpcResult("_account.getDidDocument", { token });
|
||||
},
|
||||
|
||||
deleteSession(token: AccessToken): Promise<Result<void, ApiError>> {
|
||||
return xrpcResult<void>("com.atproto.server.deleteSession", {
|
||||
method: "POST",
|
||||
token,
|
||||
});
|
||||
},
|
||||
|
||||
revokeAllSessions(
|
||||
token: AccessToken,
|
||||
): Promise<Result<{ revokedCount: number }, ApiError>> {
|
||||
return xrpcResult("_account.revokeAllSessions", {
|
||||
method: "POST",
|
||||
token,
|
||||
});
|
||||
},
|
||||
|
||||
getAccountInviteCodes(
|
||||
token: AccessToken,
|
||||
): Promise<Result<{ codes: InviteCodeInfo[] }, ApiError>> {
|
||||
return xrpcResult("com.atproto.server.getAccountInviteCodes", { token });
|
||||
},
|
||||
|
||||
createInviteCode(
|
||||
token: AccessToken,
|
||||
useCount: number = 1,
|
||||
): Promise<Result<{ code: string }, ApiError>> {
|
||||
return xrpcResult("com.atproto.server.createInviteCode", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { useCount },
|
||||
});
|
||||
},
|
||||
|
||||
changePassword(
|
||||
token: AccessToken,
|
||||
currentPassword: string,
|
||||
newPassword: string,
|
||||
): Promise<Result<void, ApiError>> {
|
||||
return xrpcResult<void>("_account.changePassword", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { currentPassword, newPassword },
|
||||
});
|
||||
},
|
||||
|
||||
getPasswordStatus(
|
||||
token: AccessToken,
|
||||
): Promise<Result<PasswordStatus, ApiError>> {
|
||||
return xrpcResult("_account.getPasswordStatus", { token });
|
||||
},
|
||||
|
||||
getServerConfig(): Promise<Result<ServerConfig, ApiError>> {
|
||||
return xrpcResult("_server.getConfig");
|
||||
},
|
||||
|
||||
getLegacyLoginPreference(
|
||||
token: AccessToken,
|
||||
): Promise<Result<LegacyLoginPreference, ApiError>> {
|
||||
return xrpcResult("_account.getLegacyLoginPreference", { token });
|
||||
},
|
||||
|
||||
updateLegacyLoginPreference(
|
||||
token: AccessToken,
|
||||
allowLegacyLogin: boolean,
|
||||
): Promise<Result<UpdateLegacyLoginResponse, ApiError>> {
|
||||
return xrpcResult("_account.updateLegacyLoginPreference", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { allowLegacyLogin },
|
||||
});
|
||||
},
|
||||
|
||||
getNotificationHistory(
|
||||
token: AccessToken,
|
||||
): Promise<Result<NotificationHistoryResponse, ApiError>> {
|
||||
return xrpcResult("_account.getNotificationHistory", { token });
|
||||
},
|
||||
|
||||
updateNotificationPrefs(
|
||||
token: AccessToken,
|
||||
prefs: {
|
||||
preferredChannel?: string;
|
||||
discordUsername?: string;
|
||||
telegramUsername?: string;
|
||||
signalUsername?: string;
|
||||
},
|
||||
): Promise<Result<UpdateNotificationPrefsResponse, ApiError>> {
|
||||
return xrpcResult("_account.updateNotificationPrefs", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: prefs,
|
||||
});
|
||||
},
|
||||
|
||||
revokeTrustedDevice(
|
||||
token: AccessToken,
|
||||
deviceId: string,
|
||||
): Promise<Result<SuccessResponse, ApiError>> {
|
||||
return xrpcResult("_account.revokeTrustedDevice", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { deviceId },
|
||||
});
|
||||
},
|
||||
|
||||
updateTrustedDevice(
|
||||
token: AccessToken,
|
||||
deviceId: string,
|
||||
friendlyName: string,
|
||||
): Promise<Result<SuccessResponse, ApiError>> {
|
||||
return xrpcResult("_account.updateTrustedDevice", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { deviceId, friendlyName },
|
||||
});
|
||||
},
|
||||
|
||||
reauthPassword(
|
||||
token: AccessToken,
|
||||
password: string,
|
||||
): Promise<Result<ReauthResponse, ApiError>> {
|
||||
return xrpcResult("_account.reauthPassword", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { password },
|
||||
});
|
||||
},
|
||||
|
||||
reauthTotp(
|
||||
token: AccessToken,
|
||||
code: string,
|
||||
): Promise<Result<ReauthResponse, ApiError>> {
|
||||
return xrpcResult("_account.reauthTotp", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { code },
|
||||
});
|
||||
},
|
||||
|
||||
reauthPasskeyStart(
|
||||
token: AccessToken,
|
||||
): Promise<Result<ReauthPasskeyStartResponse, ApiError>> {
|
||||
return xrpcResult("_account.reauthPasskeyStart", {
|
||||
method: "POST",
|
||||
token,
|
||||
});
|
||||
},
|
||||
|
||||
reauthPasskeyFinish(
|
||||
token: AccessToken,
|
||||
credential: unknown,
|
||||
): Promise<Result<ReauthResponse, ApiError>> {
|
||||
return xrpcResult("_account.reauthPasskeyFinish", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { credential },
|
||||
});
|
||||
},
|
||||
|
||||
confirmSignup(
|
||||
did: Did,
|
||||
verificationCode: string,
|
||||
): Promise<Result<ConfirmSignupResult, ApiError>> {
|
||||
return xrpcResult("com.atproto.server.confirmSignup", {
|
||||
method: "POST",
|
||||
body: { did, verificationCode },
|
||||
});
|
||||
},
|
||||
|
||||
resendVerification(
|
||||
did: Did,
|
||||
): Promise<Result<{ success: boolean }, ApiError>> {
|
||||
return xrpcResult("com.atproto.server.resendVerification", {
|
||||
method: "POST",
|
||||
body: { did },
|
||||
});
|
||||
},
|
||||
|
||||
requestEmailUpdate(
|
||||
token: AccessToken,
|
||||
): Promise<Result<EmailUpdateResponse, ApiError>> {
|
||||
return xrpcResult("com.atproto.server.requestEmailUpdate", {
|
||||
method: "POST",
|
||||
token,
|
||||
});
|
||||
},
|
||||
|
||||
updateEmail(
|
||||
token: AccessToken,
|
||||
email: string,
|
||||
emailToken?: string,
|
||||
): Promise<Result<void, ApiError>> {
|
||||
return xrpcResult<void>("com.atproto.server.updateEmail", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { email, token: emailToken },
|
||||
});
|
||||
},
|
||||
|
||||
requestAccountDelete(token: AccessToken): Promise<Result<void, ApiError>> {
|
||||
return xrpcResult<void>("com.atproto.server.requestAccountDelete", {
|
||||
method: "POST",
|
||||
token,
|
||||
});
|
||||
},
|
||||
|
||||
deleteAccount(
|
||||
did: Did,
|
||||
password: string,
|
||||
deleteToken: string,
|
||||
): Promise<Result<void, ApiError>> {
|
||||
return xrpcResult<void>("com.atproto.server.deleteAccount", {
|
||||
method: "POST",
|
||||
body: { did, password, token: deleteToken },
|
||||
});
|
||||
},
|
||||
|
||||
updateDidDocument(
|
||||
token: AccessToken,
|
||||
params: {
|
||||
verificationMethods?: VerificationMethod[];
|
||||
alsoKnownAs?: string[];
|
||||
serviceEndpoint?: string;
|
||||
},
|
||||
): Promise<Result<SuccessResponse, ApiError>> {
|
||||
return xrpcResult("_account.updateDidDocument", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: params,
|
||||
});
|
||||
},
|
||||
|
||||
deactivateAccount(
|
||||
token: AccessToken,
|
||||
deleteAfter?: string,
|
||||
): Promise<Result<void, ApiError>> {
|
||||
return xrpcResult<void>("com.atproto.server.deactivateAccount", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { deleteAfter },
|
||||
});
|
||||
},
|
||||
|
||||
activateAccount(token: AccessToken): Promise<Result<void, ApiError>> {
|
||||
return xrpcResult<void>("com.atproto.server.activateAccount", {
|
||||
method: "POST",
|
||||
token,
|
||||
});
|
||||
},
|
||||
|
||||
createRecord(
|
||||
token: AccessToken,
|
||||
repo: Did,
|
||||
collection: Nsid,
|
||||
record: unknown,
|
||||
rkey?: Rkey,
|
||||
): Promise<Result<CreateRecordResponse, ApiError>> {
|
||||
return xrpcResult("com.atproto.repo.createRecord", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { repo, collection, record, rkey },
|
||||
});
|
||||
},
|
||||
|
||||
putRecord(
|
||||
token: AccessToken,
|
||||
repo: Did,
|
||||
collection: Nsid,
|
||||
rkey: Rkey,
|
||||
record: unknown,
|
||||
): Promise<Result<CreateRecordResponse, ApiError>> {
|
||||
return xrpcResult("com.atproto.repo.putRecord", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { repo, collection, rkey, record },
|
||||
});
|
||||
},
|
||||
|
||||
getInviteCodes(
|
||||
token: AccessToken,
|
||||
options?: { sort?: "recent" | "usage"; cursor?: string; limit?: number },
|
||||
): Promise<Result<GetInviteCodesResponse, ApiError>> {
|
||||
const params: Record<string, string> = {};
|
||||
if (options?.sort) params.sort = options.sort;
|
||||
if (options?.cursor) params.cursor = options.cursor;
|
||||
if (options?.limit) params.limit = String(options.limit);
|
||||
return xrpcResult("com.atproto.admin.getInviteCodes", { token, params });
|
||||
},
|
||||
|
||||
disableAccountInvites(
|
||||
token: AccessToken,
|
||||
account: Did,
|
||||
): Promise<Result<void, ApiError>> {
|
||||
return xrpcResult<void>("com.atproto.admin.disableAccountInvites", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { account },
|
||||
});
|
||||
},
|
||||
|
||||
enableAccountInvites(
|
||||
token: AccessToken,
|
||||
account: Did,
|
||||
): Promise<Result<void, ApiError>> {
|
||||
return xrpcResult<void>("com.atproto.admin.enableAccountInvites", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { account },
|
||||
});
|
||||
},
|
||||
|
||||
adminDeleteAccount(
|
||||
token: AccessToken,
|
||||
did: Did,
|
||||
): Promise<Result<void, ApiError>> {
|
||||
return xrpcResult<void>("com.atproto.admin.deleteAccount", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { did },
|
||||
});
|
||||
},
|
||||
|
||||
startPasskeyRegistration(
|
||||
token: AccessToken,
|
||||
friendlyName?: string,
|
||||
): Promise<Result<StartPasskeyRegistrationResponse, ApiError>> {
|
||||
return xrpcResult("com.atproto.server.startPasskeyRegistration", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { friendlyName },
|
||||
});
|
||||
},
|
||||
|
||||
finishPasskeyRegistration(
|
||||
token: AccessToken,
|
||||
credential: unknown,
|
||||
friendlyName?: string,
|
||||
): Promise<Result<FinishPasskeyRegistrationResponse, ApiError>> {
|
||||
return xrpcResult("com.atproto.server.finishPasskeyRegistration", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { credential, friendlyName },
|
||||
});
|
||||
},
|
||||
|
||||
updatePasskey(
|
||||
token: AccessToken,
|
||||
id: string,
|
||||
friendlyName: string,
|
||||
): Promise<Result<void, ApiError>> {
|
||||
return xrpcResult<void>("com.atproto.server.updatePasskey", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { id, friendlyName },
|
||||
});
|
||||
},
|
||||
|
||||
regenerateBackupCodes(
|
||||
token: AccessToken,
|
||||
password: string,
|
||||
code: string,
|
||||
): Promise<Result<RegenerateBackupCodesResponse, ApiError>> {
|
||||
return xrpcResult("com.atproto.server.regenerateBackupCodes", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { password, code },
|
||||
});
|
||||
},
|
||||
|
||||
updateLocale(
|
||||
token: AccessToken,
|
||||
preferredLocale: string,
|
||||
): Promise<Result<UpdateLocaleResponse, ApiError>> {
|
||||
return xrpcResult("_account.updateLocale", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { preferredLocale },
|
||||
});
|
||||
},
|
||||
|
||||
confirmChannelVerification(
|
||||
token: AccessToken,
|
||||
channel: string,
|
||||
identifier: string,
|
||||
code: string,
|
||||
): Promise<Result<SuccessResponse, ApiError>> {
|
||||
return xrpcResult("_account.confirmChannelVerification", {
|
||||
method: "POST",
|
||||
token,
|
||||
body: { channel, identifier, code },
|
||||
});
|
||||
},
|
||||
|
||||
removePassword(
|
||||
token: AccessToken,
|
||||
): Promise<Result<SuccessResponse, ApiError>> {
|
||||
return xrpcResult("_account.removePassword", {
|
||||
method: "POST",
|
||||
token,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { navigate, routes } from '../lib/router.svelte'
|
||||
import { _ } from '../lib/i18n'
|
||||
|
||||
let code = $state('')
|
||||
let submitting = $state(false)
|
||||
let error = $state<string | null>(null)
|
||||
|
||||
function getRequestUri(): string | null {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
return params.get('request_uri')
|
||||
}
|
||||
|
||||
function getChannel(): string {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
return params.get('channel') || 'email'
|
||||
}
|
||||
|
||||
async function handleSubmit(e: Event) {
|
||||
e.preventDefault()
|
||||
const requestUri = getRequestUri()
|
||||
if (!requestUri) {
|
||||
error = $_('oauth.twoFactorCode.errors.missingRequestUri')
|
||||
return
|
||||
}
|
||||
|
||||
submitting = true
|
||||
error = null
|
||||
|
||||
try {
|
||||
const response = await fetch('/oauth/authorize/2fa', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
request_uri: requestUri,
|
||||
code: code.trim()
|
||||
})
|
||||
})
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
error = data.error_description || data.error || $_('oauth.twoFactorCode.errors.verificationFailed')
|
||||
submitting = false
|
||||
return
|
||||
}
|
||||
|
||||
if (data.redirect_uri) {
|
||||
window.location.href = data.redirect_uri
|
||||
return
|
||||
}
|
||||
|
||||
error = $_('oauth.twoFactorCode.errors.unexpectedResponse')
|
||||
submitting = false
|
||||
} catch {
|
||||
error = $_('oauth.twoFactorCode.errors.connectionFailed')
|
||||
submitting = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
const requestUri = getRequestUri()
|
||||
if (requestUri) {
|
||||
navigate(routes.oauthLogin, { params: { request_uri: requestUri } })
|
||||
} else {
|
||||
window.history.back()
|
||||
}
|
||||
}
|
||||
|
||||
let channel = $derived(getChannel())
|
||||
</script>
|
||||
|
||||
<div class="oauth-2fa-container">
|
||||
<h1>{$_('oauth.twoFactorCode.title')}</h1>
|
||||
<p class="subtitle">
|
||||
{$_('oauth.twoFactorCode.subtitle', { values: { channel } })}
|
||||
</p>
|
||||
|
||||
{#if error}
|
||||
<div class="error">{error}</div>
|
||||
{/if}
|
||||
|
||||
<form onsubmit={handleSubmit}>
|
||||
<div>
|
||||
<label for="code">{$_('oauth.twoFactorCode.codeLabel')}</label>
|
||||
<input
|
||||
id="code"
|
||||
type="text"
|
||||
bind:value={code}
|
||||
placeholder={$_('oauth.twoFactorCode.codePlaceholder')}
|
||||
disabled={submitting}
|
||||
required
|
||||
maxlength="6"
|
||||
pattern="[0-9]{6}"
|
||||
autocomplete="one-time-code"
|
||||
inputmode="numeric"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<button type="button" class="cancel" onclick={handleCancel} disabled={submitting}>
|
||||
{$_('common.cancel')}
|
||||
</button>
|
||||
<button type="submit" disabled={submitting || code.trim().length !== 6}>
|
||||
{submitting ? $_('common.verifying') : $_('common.verify')}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -1,121 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { navigate, routes } from '../lib/router.svelte'
|
||||
import { _ } from '../lib/i18n'
|
||||
|
||||
let code = $state('')
|
||||
let trustDevice = $state(false)
|
||||
let submitting = $state(false)
|
||||
let error = $state<string | null>(null)
|
||||
|
||||
function getRequestUri(): string | null {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
return params.get('request_uri')
|
||||
}
|
||||
|
||||
async function handleSubmit(e: Event) {
|
||||
e.preventDefault()
|
||||
const requestUri = getRequestUri()
|
||||
if (!requestUri) {
|
||||
error = $_('common.error')
|
||||
return
|
||||
}
|
||||
|
||||
submitting = true
|
||||
error = null
|
||||
|
||||
try {
|
||||
const response = await fetch('/oauth/authorize/2fa', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
request_uri: requestUri,
|
||||
code: code.trim().toUpperCase(),
|
||||
trust_device: trustDevice
|
||||
})
|
||||
})
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
error = data.error_description || data.error || $_('common.error')
|
||||
submitting = false
|
||||
return
|
||||
}
|
||||
|
||||
if (data.redirect_uri) {
|
||||
window.location.href = data.redirect_uri
|
||||
return
|
||||
}
|
||||
|
||||
error = $_('common.error')
|
||||
submitting = false
|
||||
} catch {
|
||||
error = $_('common.error')
|
||||
submitting = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
const requestUri = getRequestUri()
|
||||
if (requestUri) {
|
||||
navigate(routes.oauthLogin, { params: { request_uri: requestUri } })
|
||||
} else {
|
||||
window.history.back()
|
||||
}
|
||||
}
|
||||
|
||||
let isBackupCode = $derived(code.trim().length === 8 && /^[A-Z0-9]+$/i.test(code.trim()))
|
||||
let isTotpCode = $derived(code.trim().length === 6 && /^[0-9]+$/.test(code.trim()))
|
||||
let canSubmit = $derived(isBackupCode || isTotpCode)
|
||||
</script>
|
||||
|
||||
<div class="oauth-totp-container">
|
||||
<h1>{$_('oauth.totp.title')}</h1>
|
||||
|
||||
{#if error}
|
||||
<div class="error">{error}</div>
|
||||
{/if}
|
||||
|
||||
<form onsubmit={handleSubmit}>
|
||||
<div>
|
||||
<label for="code">{$_('oauth.totp.codePlaceholder')}</label>
|
||||
<input
|
||||
id="code"
|
||||
type="text"
|
||||
bind:value={code}
|
||||
placeholder={isBackupCode ? $_('oauth.totp.backupCodePlaceholder') : $_('oauth.totp.codePlaceholder')}
|
||||
disabled={submitting}
|
||||
required
|
||||
maxlength="8"
|
||||
autocomplete="one-time-code"
|
||||
autocapitalize="characters"
|
||||
/>
|
||||
{#if isBackupCode || isTotpCode}
|
||||
<p class="hint">
|
||||
{isBackupCode ? $_('oauth.totp.hintBackupCode') : $_('oauth.totp.hintTotpCode')}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<label class="trust-device-label">
|
||||
<input
|
||||
type="checkbox"
|
||||
bind:checked={trustDevice}
|
||||
disabled={submitting}
|
||||
/>
|
||||
<span>{$_('oauth.totp.trustDevice')}</span>
|
||||
</label>
|
||||
|
||||
<div class="actions">
|
||||
<button type="button" class="cancel" onclick={handleCancel} disabled={submitting}>
|
||||
{$_('common.cancel')}
|
||||
</button>
|
||||
<button type="submit" disabled={submitting || !canSubmit}>
|
||||
{submitting ? $_('common.verifying') : $_('common.verify')}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -1,27 +0,0 @@
|
||||
<script lang="ts">
|
||||
import { startOAuthRegister } from '../lib/oauth'
|
||||
import { _ } from '../lib/i18n'
|
||||
|
||||
let error = $state<string | null>(null)
|
||||
let initiated = false
|
||||
|
||||
$effect(() => {
|
||||
if (!initiated) {
|
||||
initiated = true
|
||||
startOAuthRegister().catch((err) => {
|
||||
error = err instanceof Error ? err.message : 'Failed to start registration'
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="register-redirect">
|
||||
{#if error}
|
||||
<div class="message error">{error}</div>
|
||||
<a href="/app/login">{$_('register.signIn')}</a>
|
||||
{:else}
|
||||
<div class="loading-content">
|
||||
<p>{$_('common.loading')}</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
Reference in New Issue
Block a user