+12
-894
Diff
round #2
+12
-634
frontend/src/lib/api.ts
+12
-634
frontend/src/lib/api.ts
···
441
441
params: {
442
442
did: Did;
443
443
handle: Handle;
444
-
email: EmailAddress;
444
+
email?: EmailAddress;
445
445
password: string;
446
446
inviteCode?: string;
447
+
verificationChannel?: string;
448
+
discordUsername?: string;
449
+
telegramUsername?: string;
450
+
signalUsername?: string;
447
451
},
448
452
): Promise<Session> {
449
453
const url = `${API_BASE}/com.atproto.server.createAccount`;
···
459
463
email: params.email,
460
464
password: params.password,
461
465
inviteCode: params.inviteCode,
466
+
verificationChannel: params.verificationChannel,
467
+
discordUsername: params.discordUsername,
468
+
telegramUsername: params.telegramUsername,
469
+
signalUsername: params.signalUsername,
462
470
}),
463
471
});
464
472
const data = await response.json();
···
1231
1239
},
1232
1240
1233
1241
resendMigrationVerification(
1234
-
email: EmailAddress,
1242
+
channel: string,
1243
+
identifier: string,
1235
1244
): Promise<ResendMigrationVerificationResponse> {
1236
1245
return xrpc("com.atproto.server.resendMigrationVerification", {
1237
1246
method: "POST",
1238
-
body: { email },
1247
+
body: { channel, identifier },
1239
1248
});
1240
1249
},
1241
1250
···
1509
1518
},
1510
1519
1511
1520
};
1512
-
1513
-
export const typedApi = {
1514
-
createSession(
1515
-
identifier: string,
1516
-
password: string,
1517
-
): Promise<Result<Session, ApiError>> {
1518
-
return xrpcResult<Session>("com.atproto.server.createSession", {
1519
-
method: "POST",
1520
-
body: { identifier, password },
1521
-
}).then((r) => r.ok ? ok(castSession(r.value)) : r);
1522
-
},
1523
-
1524
-
getSession(token: AccessToken): Promise<Result<Session, ApiError>> {
1525
-
return xrpcResult<Session>("com.atproto.server.getSession", { token })
1526
-
.then((r) => r.ok ? ok(castSession(r.value)) : r);
1527
-
},
1528
-
1529
-
refreshSession(refreshJwt: RefreshToken): Promise<Result<Session, ApiError>> {
1530
-
return xrpcResult<Session>("com.atproto.server.refreshSession", {
1531
-
method: "POST",
1532
-
token: refreshJwt,
1533
-
}).then((r) => r.ok ? ok(castSession(r.value)) : r);
1534
-
},
1535
-
1536
-
describeServer(): Promise<Result<ServerDescription, ApiError>> {
1537
-
return xrpcResult("com.atproto.server.describeServer");
1538
-
},
1539
-
1540
-
listAppPasswords(
1541
-
token: AccessToken,
1542
-
): Promise<Result<{ passwords: AppPassword[] }, ApiError>> {
1543
-
return xrpcResult("com.atproto.server.listAppPasswords", { token });
1544
-
},
1545
-
1546
-
createAppPassword(
1547
-
token: AccessToken,
1548
-
name: string,
1549
-
scopes?: string,
1550
-
): Promise<Result<CreatedAppPassword, ApiError>> {
1551
-
return xrpcResult("com.atproto.server.createAppPassword", {
1552
-
method: "POST",
1553
-
token,
1554
-
body: { name, scopes },
1555
-
});
1556
-
},
1557
-
1558
-
revokeAppPassword(
1559
-
token: AccessToken,
1560
-
name: string,
1561
-
): Promise<Result<void, ApiError>> {
1562
-
return xrpcResult<void>("com.atproto.server.revokeAppPassword", {
1563
-
method: "POST",
1564
-
token,
1565
-
body: { name },
1566
-
});
1567
-
},
1568
-
1569
-
listSessions(
1570
-
token: AccessToken,
1571
-
): Promise<Result<ListSessionsResponse, ApiError>> {
1572
-
return xrpcResult("_account.listSessions", { token });
1573
-
},
1574
-
1575
-
revokeSession(
1576
-
token: AccessToken,
1577
-
sessionId: string,
1578
-
): Promise<Result<void, ApiError>> {
1579
-
return xrpcResult<void>("_account.revokeSession", {
1580
-
method: "POST",
1581
-
token,
1582
-
body: { sessionId },
1583
-
});
1584
-
},
1585
-
1586
-
getTotpStatus(token: AccessToken): Promise<Result<TotpStatus, ApiError>> {
1587
-
return xrpcResult("com.atproto.server.getTotpStatus", { token });
1588
-
},
1589
-
1590
-
createTotpSecret(token: AccessToken): Promise<Result<TotpSecret, ApiError>> {
1591
-
return xrpcResult("com.atproto.server.createTotpSecret", {
1592
-
method: "POST",
1593
-
token,
1594
-
});
1595
-
},
1596
-
1597
-
enableTotp(
1598
-
token: AccessToken,
1599
-
code: string,
1600
-
): Promise<Result<EnableTotpResponse, ApiError>> {
1601
-
return xrpcResult("com.atproto.server.enableTotp", {
1602
-
method: "POST",
1603
-
token,
1604
-
body: { code },
1605
-
});
1606
-
},
1607
-
1608
-
disableTotp(
1609
-
token: AccessToken,
1610
-
password: string,
1611
-
code: string,
1612
-
): Promise<Result<SuccessResponse, ApiError>> {
1613
-
return xrpcResult("com.atproto.server.disableTotp", {
1614
-
method: "POST",
1615
-
token,
1616
-
body: { password, code },
1617
-
});
1618
-
},
1619
-
1620
-
listPasskeys(
1621
-
token: AccessToken,
1622
-
): Promise<Result<ListPasskeysResponse, ApiError>> {
1623
-
return xrpcResult("com.atproto.server.listPasskeys", { token });
1624
-
},
1625
-
1626
-
deletePasskey(
1627
-
token: AccessToken,
1628
-
id: string,
1629
-
): Promise<Result<void, ApiError>> {
1630
-
return xrpcResult<void>("com.atproto.server.deletePasskey", {
1631
-
method: "POST",
1632
-
token,
1633
-
body: { id },
1634
-
});
1635
-
},
1636
-
1637
-
listTrustedDevices(
1638
-
token: AccessToken,
1639
-
): Promise<Result<ListTrustedDevicesResponse, ApiError>> {
1640
-
return xrpcResult("_account.listTrustedDevices", { token });
1641
-
},
1642
-
1643
-
getReauthStatus(token: AccessToken): Promise<Result<ReauthStatus, ApiError>> {
1644
-
return xrpcResult("_account.getReauthStatus", { token });
1645
-
},
1646
-
1647
-
getNotificationPrefs(
1648
-
token: AccessToken,
1649
-
): Promise<Result<NotificationPrefs, ApiError>> {
1650
-
return xrpcResult("_account.getNotificationPrefs", { token });
1651
-
},
1652
-
1653
-
updateHandle(
1654
-
token: AccessToken,
1655
-
handle: Handle,
1656
-
): Promise<Result<void, ApiError>> {
1657
-
return xrpcResult<void>("com.atproto.identity.updateHandle", {
1658
-
method: "POST",
1659
-
token,
1660
-
body: { handle },
1661
-
});
1662
-
},
1663
-
1664
-
describeRepo(
1665
-
token: AccessToken,
1666
-
repo: Did,
1667
-
): Promise<Result<RepoDescription, ApiError>> {
1668
-
return xrpcResult("com.atproto.repo.describeRepo", {
1669
-
token,
1670
-
params: { repo },
1671
-
});
1672
-
},
1673
-
1674
-
listRecords(
1675
-
token: AccessToken,
1676
-
repo: Did,
1677
-
collection: Nsid,
1678
-
options?: { limit?: number; cursor?: string; reverse?: boolean },
1679
-
): Promise<Result<ListRecordsResponse, ApiError>> {
1680
-
const params: Record<string, string> = { repo, collection };
1681
-
if (options?.limit) params.limit = String(options.limit);
1682
-
if (options?.cursor) params.cursor = options.cursor;
1683
-
if (options?.reverse) params.reverse = "true";
1684
-
return xrpcResult("com.atproto.repo.listRecords", { token, params });
1685
-
},
1686
-
1687
-
getRecord(
1688
-
token: AccessToken,
1689
-
repo: Did,
1690
-
collection: Nsid,
1691
-
rkey: Rkey,
1692
-
): Promise<Result<RecordResponse, ApiError>> {
1693
-
return xrpcResult("com.atproto.repo.getRecord", {
1694
-
token,
1695
-
params: { repo, collection, rkey },
1696
-
});
1697
-
},
1698
-
1699
-
deleteRecord(
1700
-
token: AccessToken,
1701
-
repo: Did,
1702
-
collection: Nsid,
1703
-
rkey: Rkey,
1704
-
): Promise<Result<void, ApiError>> {
1705
-
return xrpcResult<void>("com.atproto.repo.deleteRecord", {
1706
-
method: "POST",
1707
-
token,
1708
-
body: { repo, collection, rkey },
1709
-
});
1710
-
},
1711
-
1712
-
searchAccounts(
1713
-
token: AccessToken,
1714
-
options?: { handle?: string; cursor?: string; limit?: number },
1715
-
): Promise<Result<SearchAccountsResponse, ApiError>> {
1716
-
const params: Record<string, string> = {};
1717
-
if (options?.handle) params.handle = options.handle;
1718
-
if (options?.cursor) params.cursor = options.cursor;
1719
-
if (options?.limit) params.limit = String(options.limit);
1720
-
return xrpcResult("com.atproto.admin.searchAccounts", { token, params });
1721
-
},
1722
-
1723
-
getAccountInfo(
1724
-
token: AccessToken,
1725
-
did: Did,
1726
-
): Promise<Result<AccountInfo, ApiError>> {
1727
-
return xrpcResult("com.atproto.admin.getAccountInfo", {
1728
-
token,
1729
-
params: { did },
1730
-
});
1731
-
},
1732
-
1733
-
getServerStats(token: AccessToken): Promise<Result<ServerStats, ApiError>> {
1734
-
return xrpcResult("_admin.getServerStats", { token });
1735
-
},
1736
-
1737
-
getDidDocument(token: AccessToken): Promise<Result<DidDocument, ApiError>> {
1738
-
return xrpcResult("_account.getDidDocument", { token });
1739
-
},
1740
-
1741
-
deleteSession(token: AccessToken): Promise<Result<void, ApiError>> {
1742
-
return xrpcResult<void>("com.atproto.server.deleteSession", {
1743
-
method: "POST",
1744
-
token,
1745
-
});
1746
-
},
1747
-
1748
-
revokeAllSessions(
1749
-
token: AccessToken,
1750
-
): Promise<Result<{ revokedCount: number }, ApiError>> {
1751
-
return xrpcResult("_account.revokeAllSessions", {
1752
-
method: "POST",
1753
-
token,
1754
-
});
1755
-
},
1756
-
1757
-
getAccountInviteCodes(
1758
-
token: AccessToken,
1759
-
): Promise<Result<{ codes: InviteCodeInfo[] }, ApiError>> {
1760
-
return xrpcResult("com.atproto.server.getAccountInviteCodes", { token });
1761
-
},
1762
-
1763
-
createInviteCode(
1764
-
token: AccessToken,
1765
-
useCount: number = 1,
1766
-
): Promise<Result<{ code: string }, ApiError>> {
1767
-
return xrpcResult("com.atproto.server.createInviteCode", {
1768
-
method: "POST",
1769
-
token,
1770
-
body: { useCount },
1771
-
});
1772
-
},
1773
-
1774
-
changePassword(
1775
-
token: AccessToken,
1776
-
currentPassword: string,
1777
-
newPassword: string,
1778
-
): Promise<Result<void, ApiError>> {
1779
-
return xrpcResult<void>("_account.changePassword", {
1780
-
method: "POST",
1781
-
token,
1782
-
body: { currentPassword, newPassword },
1783
-
});
1784
-
},
1785
-
1786
-
getPasswordStatus(
1787
-
token: AccessToken,
1788
-
): Promise<Result<PasswordStatus, ApiError>> {
1789
-
return xrpcResult("_account.getPasswordStatus", { token });
1790
-
},
1791
-
1792
-
getServerConfig(): Promise<Result<ServerConfig, ApiError>> {
1793
-
return xrpcResult("_server.getConfig");
1794
-
},
1795
-
1796
-
getLegacyLoginPreference(
1797
-
token: AccessToken,
1798
-
): Promise<Result<LegacyLoginPreference, ApiError>> {
1799
-
return xrpcResult("_account.getLegacyLoginPreference", { token });
1800
-
},
1801
-
1802
-
updateLegacyLoginPreference(
1803
-
token: AccessToken,
1804
-
allowLegacyLogin: boolean,
1805
-
): Promise<Result<UpdateLegacyLoginResponse, ApiError>> {
1806
-
return xrpcResult("_account.updateLegacyLoginPreference", {
1807
-
method: "POST",
1808
-
token,
1809
-
body: { allowLegacyLogin },
1810
-
});
1811
-
},
1812
-
1813
-
getNotificationHistory(
1814
-
token: AccessToken,
1815
-
): Promise<Result<NotificationHistoryResponse, ApiError>> {
1816
-
return xrpcResult("_account.getNotificationHistory", { token });
1817
-
},
1818
-
1819
-
updateNotificationPrefs(
1820
-
token: AccessToken,
1821
-
prefs: {
1822
-
preferredChannel?: string;
1823
-
discordUsername?: string;
1824
-
telegramUsername?: string;
1825
-
signalUsername?: string;
1826
-
},
1827
-
): Promise<Result<UpdateNotificationPrefsResponse, ApiError>> {
1828
-
return xrpcResult("_account.updateNotificationPrefs", {
1829
-
method: "POST",
1830
-
token,
1831
-
body: prefs,
1832
-
});
1833
-
},
1834
-
1835
-
revokeTrustedDevice(
1836
-
token: AccessToken,
1837
-
deviceId: string,
1838
-
): Promise<Result<SuccessResponse, ApiError>> {
1839
-
return xrpcResult("_account.revokeTrustedDevice", {
1840
-
method: "POST",
1841
-
token,
1842
-
body: { deviceId },
1843
-
});
1844
-
},
1845
-
1846
-
updateTrustedDevice(
1847
-
token: AccessToken,
1848
-
deviceId: string,
1849
-
friendlyName: string,
1850
-
): Promise<Result<SuccessResponse, ApiError>> {
1851
-
return xrpcResult("_account.updateTrustedDevice", {
1852
-
method: "POST",
1853
-
token,
1854
-
body: { deviceId, friendlyName },
1855
-
});
1856
-
},
1857
-
1858
-
reauthPassword(
1859
-
token: AccessToken,
1860
-
password: string,
1861
-
): Promise<Result<ReauthResponse, ApiError>> {
1862
-
return xrpcResult("_account.reauthPassword", {
1863
-
method: "POST",
1864
-
token,
1865
-
body: { password },
1866
-
});
1867
-
},
1868
-
1869
-
reauthTotp(
1870
-
token: AccessToken,
1871
-
code: string,
1872
-
): Promise<Result<ReauthResponse, ApiError>> {
1873
-
return xrpcResult("_account.reauthTotp", {
1874
-
method: "POST",
1875
-
token,
1876
-
body: { code },
1877
-
});
1878
-
},
1879
-
1880
-
reauthPasskeyStart(
1881
-
token: AccessToken,
1882
-
): Promise<Result<ReauthPasskeyStartResponse, ApiError>> {
1883
-
return xrpcResult("_account.reauthPasskeyStart", {
1884
-
method: "POST",
1885
-
token,
1886
-
});
1887
-
},
1888
-
1889
-
reauthPasskeyFinish(
1890
-
token: AccessToken,
1891
-
credential: unknown,
1892
-
): Promise<Result<ReauthResponse, ApiError>> {
1893
-
return xrpcResult("_account.reauthPasskeyFinish", {
1894
-
method: "POST",
1895
-
token,
1896
-
body: { credential },
1897
-
});
1898
-
},
1899
-
1900
-
confirmSignup(
1901
-
did: Did,
1902
-
verificationCode: string,
1903
-
): Promise<Result<ConfirmSignupResult, ApiError>> {
1904
-
return xrpcResult("com.atproto.server.confirmSignup", {
1905
-
method: "POST",
1906
-
body: { did, verificationCode },
1907
-
});
1908
-
},
1909
-
1910
-
resendVerification(
1911
-
did: Did,
1912
-
): Promise<Result<{ success: boolean }, ApiError>> {
1913
-
return xrpcResult("com.atproto.server.resendVerification", {
1914
-
method: "POST",
1915
-
body: { did },
1916
-
});
1917
-
},
1918
-
1919
-
requestEmailUpdate(
1920
-
token: AccessToken,
1921
-
): Promise<Result<EmailUpdateResponse, ApiError>> {
1922
-
return xrpcResult("com.atproto.server.requestEmailUpdate", {
1923
-
method: "POST",
1924
-
token,
1925
-
});
1926
-
},
1927
-
1928
-
updateEmail(
1929
-
token: AccessToken,
1930
-
email: string,
1931
-
emailToken?: string,
1932
-
): Promise<Result<void, ApiError>> {
1933
-
return xrpcResult<void>("com.atproto.server.updateEmail", {
1934
-
method: "POST",
1935
-
token,
1936
-
body: { email, token: emailToken },
1937
-
});
1938
-
},
1939
-
1940
-
requestAccountDelete(token: AccessToken): Promise<Result<void, ApiError>> {
1941
-
return xrpcResult<void>("com.atproto.server.requestAccountDelete", {
1942
-
method: "POST",
1943
-
token,
1944
-
});
1945
-
},
1946
-
1947
-
deleteAccount(
1948
-
did: Did,
1949
-
password: string,
1950
-
deleteToken: string,
1951
-
): Promise<Result<void, ApiError>> {
1952
-
return xrpcResult<void>("com.atproto.server.deleteAccount", {
1953
-
method: "POST",
1954
-
body: { did, password, token: deleteToken },
1955
-
});
1956
-
},
1957
-
1958
-
updateDidDocument(
1959
-
token: AccessToken,
1960
-
params: {
1961
-
verificationMethods?: VerificationMethod[];
1962
-
alsoKnownAs?: string[];
1963
-
serviceEndpoint?: string;
1964
-
},
1965
-
): Promise<Result<SuccessResponse, ApiError>> {
1966
-
return xrpcResult("_account.updateDidDocument", {
1967
-
method: "POST",
1968
-
token,
1969
-
body: params,
1970
-
});
1971
-
},
1972
-
1973
-
deactivateAccount(
1974
-
token: AccessToken,
1975
-
deleteAfter?: string,
1976
-
): Promise<Result<void, ApiError>> {
1977
-
return xrpcResult<void>("com.atproto.server.deactivateAccount", {
1978
-
method: "POST",
1979
-
token,
1980
-
body: { deleteAfter },
1981
-
});
1982
-
},
1983
-
1984
-
activateAccount(token: AccessToken): Promise<Result<void, ApiError>> {
1985
-
return xrpcResult<void>("com.atproto.server.activateAccount", {
1986
-
method: "POST",
1987
-
token,
1988
-
});
1989
-
},
1990
-
1991
-
createRecord(
1992
-
token: AccessToken,
1993
-
repo: Did,
1994
-
collection: Nsid,
1995
-
record: unknown,
1996
-
rkey?: Rkey,
1997
-
): Promise<Result<CreateRecordResponse, ApiError>> {
1998
-
return xrpcResult("com.atproto.repo.createRecord", {
1999
-
method: "POST",
2000
-
token,
2001
-
body: { repo, collection, record, rkey },
2002
-
});
2003
-
},
2004
-
2005
-
putRecord(
2006
-
token: AccessToken,
2007
-
repo: Did,
2008
-
collection: Nsid,
2009
-
rkey: Rkey,
2010
-
record: unknown,
2011
-
): Promise<Result<CreateRecordResponse, ApiError>> {
2012
-
return xrpcResult("com.atproto.repo.putRecord", {
2013
-
method: "POST",
2014
-
token,
2015
-
body: { repo, collection, rkey, record },
2016
-
});
2017
-
},
2018
-
2019
-
getInviteCodes(
2020
-
token: AccessToken,
2021
-
options?: { sort?: "recent" | "usage"; cursor?: string; limit?: number },
2022
-
): Promise<Result<GetInviteCodesResponse, ApiError>> {
2023
-
const params: Record<string, string> = {};
2024
-
if (options?.sort) params.sort = options.sort;
2025
-
if (options?.cursor) params.cursor = options.cursor;
2026
-
if (options?.limit) params.limit = String(options.limit);
2027
-
return xrpcResult("com.atproto.admin.getInviteCodes", { token, params });
2028
-
},
2029
-
2030
-
disableAccountInvites(
2031
-
token: AccessToken,
2032
-
account: Did,
2033
-
): Promise<Result<void, ApiError>> {
2034
-
return xrpcResult<void>("com.atproto.admin.disableAccountInvites", {
2035
-
method: "POST",
2036
-
token,
2037
-
body: { account },
2038
-
});
2039
-
},
2040
-
2041
-
enableAccountInvites(
2042
-
token: AccessToken,
2043
-
account: Did,
2044
-
): Promise<Result<void, ApiError>> {
2045
-
return xrpcResult<void>("com.atproto.admin.enableAccountInvites", {
2046
-
method: "POST",
2047
-
token,
2048
-
body: { account },
2049
-
});
2050
-
},
2051
-
2052
-
adminDeleteAccount(
2053
-
token: AccessToken,
2054
-
did: Did,
2055
-
): Promise<Result<void, ApiError>> {
2056
-
return xrpcResult<void>("com.atproto.admin.deleteAccount", {
2057
-
method: "POST",
2058
-
token,
2059
-
body: { did },
2060
-
});
2061
-
},
2062
-
2063
-
startPasskeyRegistration(
2064
-
token: AccessToken,
2065
-
friendlyName?: string,
2066
-
): Promise<Result<StartPasskeyRegistrationResponse, ApiError>> {
2067
-
return xrpcResult("com.atproto.server.startPasskeyRegistration", {
2068
-
method: "POST",
2069
-
token,
2070
-
body: { friendlyName },
2071
-
});
2072
-
},
2073
-
2074
-
finishPasskeyRegistration(
2075
-
token: AccessToken,
2076
-
credential: unknown,
2077
-
friendlyName?: string,
2078
-
): Promise<Result<FinishPasskeyRegistrationResponse, ApiError>> {
2079
-
return xrpcResult("com.atproto.server.finishPasskeyRegistration", {
2080
-
method: "POST",
2081
-
token,
2082
-
body: { credential, friendlyName },
2083
-
});
2084
-
},
2085
-
2086
-
updatePasskey(
2087
-
token: AccessToken,
2088
-
id: string,
2089
-
friendlyName: string,
2090
-
): Promise<Result<void, ApiError>> {
2091
-
return xrpcResult<void>("com.atproto.server.updatePasskey", {
2092
-
method: "POST",
2093
-
token,
2094
-
body: { id, friendlyName },
2095
-
});
2096
-
},
2097
-
2098
-
regenerateBackupCodes(
2099
-
token: AccessToken,
2100
-
password: string,
2101
-
code: string,
2102
-
): Promise<Result<RegenerateBackupCodesResponse, ApiError>> {
2103
-
return xrpcResult("com.atproto.server.regenerateBackupCodes", {
2104
-
method: "POST",
2105
-
token,
2106
-
body: { password, code },
2107
-
});
2108
-
},
2109
-
2110
-
updateLocale(
2111
-
token: AccessToken,
2112
-
preferredLocale: string,
2113
-
): Promise<Result<UpdateLocaleResponse, ApiError>> {
2114
-
return xrpcResult("_account.updateLocale", {
2115
-
method: "POST",
2116
-
token,
2117
-
body: { preferredLocale },
2118
-
});
2119
-
},
2120
-
2121
-
confirmChannelVerification(
2122
-
token: AccessToken,
2123
-
channel: string,
2124
-
identifier: string,
2125
-
code: string,
2126
-
): Promise<Result<SuccessResponse, ApiError>> {
2127
-
return xrpcResult("_account.confirmChannelVerification", {
2128
-
method: "POST",
2129
-
token,
2130
-
body: { channel, identifier, code },
2131
-
});
2132
-
},
2133
-
2134
-
removePassword(
2135
-
token: AccessToken,
2136
-
): Promise<Result<SuccessResponse, ApiError>> {
2137
-
return xrpcResult("_account.removePassword", {
2138
-
method: "POST",
2139
-
token,
2140
-
});
2141
-
},
2142
-
};
-112
frontend/src/routes/OAuth2FA.svelte
-112
frontend/src/routes/OAuth2FA.svelte
···
1
-
<script lang="ts">
2
-
import { navigate, routes } from '../lib/router.svelte'
3
-
import { _ } from '../lib/i18n'
4
-
5
-
let code = $state('')
6
-
let submitting = $state(false)
7
-
let error = $state<string | null>(null)
8
-
9
-
function getRequestUri(): string | null {
10
-
const params = new URLSearchParams(window.location.search)
11
-
return params.get('request_uri')
12
-
}
13
-
14
-
function getChannel(): string {
15
-
const params = new URLSearchParams(window.location.search)
16
-
return params.get('channel') || 'email'
17
-
}
18
-
19
-
async function handleSubmit(e: Event) {
20
-
e.preventDefault()
21
-
const requestUri = getRequestUri()
22
-
if (!requestUri) {
23
-
error = $_('oauth.twoFactorCode.errors.missingRequestUri')
24
-
return
25
-
}
26
-
27
-
submitting = true
28
-
error = null
29
-
30
-
try {
31
-
const response = await fetch('/oauth/authorize/2fa', {
32
-
method: 'POST',
33
-
headers: {
34
-
'Content-Type': 'application/json',
35
-
'Accept': 'application/json'
36
-
},
37
-
body: JSON.stringify({
38
-
request_uri: requestUri,
39
-
code: code.trim()
40
-
})
41
-
})
42
-
43
-
const data = await response.json()
44
-
45
-
if (!response.ok) {
46
-
error = data.error_description || data.error || $_('oauth.twoFactorCode.errors.verificationFailed')
47
-
submitting = false
48
-
return
49
-
}
50
-
51
-
if (data.redirect_uri) {
52
-
window.location.href = data.redirect_uri
53
-
return
54
-
}
55
-
56
-
error = $_('oauth.twoFactorCode.errors.unexpectedResponse')
57
-
submitting = false
58
-
} catch {
59
-
error = $_('oauth.twoFactorCode.errors.connectionFailed')
60
-
submitting = false
61
-
}
62
-
}
63
-
64
-
function handleCancel() {
65
-
const requestUri = getRequestUri()
66
-
if (requestUri) {
67
-
navigate(routes.oauthLogin, { params: { request_uri: requestUri } })
68
-
} else {
69
-
window.history.back()
70
-
}
71
-
}
72
-
73
-
let channel = $derived(getChannel())
74
-
</script>
75
-
76
-
<div class="oauth-2fa-container">
77
-
<h1>{$_('oauth.twoFactorCode.title')}</h1>
78
-
<p class="subtitle">
79
-
{$_('oauth.twoFactorCode.subtitle', { values: { channel } })}
80
-
</p>
81
-
82
-
{#if error}
83
-
<div class="error">{error}</div>
84
-
{/if}
85
-
86
-
<form onsubmit={handleSubmit}>
87
-
<div>
88
-
<label for="code">{$_('oauth.twoFactorCode.codeLabel')}</label>
89
-
<input
90
-
id="code"
91
-
type="text"
92
-
bind:value={code}
93
-
placeholder={$_('oauth.twoFactorCode.codePlaceholder')}
94
-
disabled={submitting}
95
-
required
96
-
maxlength="6"
97
-
pattern="[0-9]{6}"
98
-
autocomplete="one-time-code"
99
-
inputmode="numeric"
100
-
/>
101
-
</div>
102
-
103
-
<div class="actions">
104
-
<button type="button" class="cancel" onclick={handleCancel} disabled={submitting}>
105
-
{$_('common.cancel')}
106
-
</button>
107
-
<button type="submit" disabled={submitting || code.trim().length !== 6}>
108
-
{submitting ? $_('common.verifying') : $_('common.verify')}
109
-
</button>
110
-
</div>
111
-
</form>
112
-
</div>
-121
frontend/src/routes/OAuthTotp.svelte
-121
frontend/src/routes/OAuthTotp.svelte
···
1
-
<script lang="ts">
2
-
import { navigate, routes } from '../lib/router.svelte'
3
-
import { _ } from '../lib/i18n'
4
-
5
-
let code = $state('')
6
-
let trustDevice = $state(false)
7
-
let submitting = $state(false)
8
-
let error = $state<string | null>(null)
9
-
10
-
function getRequestUri(): string | null {
11
-
const params = new URLSearchParams(window.location.search)
12
-
return params.get('request_uri')
13
-
}
14
-
15
-
async function handleSubmit(e: Event) {
16
-
e.preventDefault()
17
-
const requestUri = getRequestUri()
18
-
if (!requestUri) {
19
-
error = $_('common.error')
20
-
return
21
-
}
22
-
23
-
submitting = true
24
-
error = null
25
-
26
-
try {
27
-
const response = await fetch('/oauth/authorize/2fa', {
28
-
method: 'POST',
29
-
headers: {
30
-
'Content-Type': 'application/json',
31
-
'Accept': 'application/json'
32
-
},
33
-
body: JSON.stringify({
34
-
request_uri: requestUri,
35
-
code: code.trim().toUpperCase(),
36
-
trust_device: trustDevice
37
-
})
38
-
})
39
-
40
-
const data = await response.json()
41
-
42
-
if (!response.ok) {
43
-
error = data.error_description || data.error || $_('common.error')
44
-
submitting = false
45
-
return
46
-
}
47
-
48
-
if (data.redirect_uri) {
49
-
window.location.href = data.redirect_uri
50
-
return
51
-
}
52
-
53
-
error = $_('common.error')
54
-
submitting = false
55
-
} catch {
56
-
error = $_('common.error')
57
-
submitting = false
58
-
}
59
-
}
60
-
61
-
function handleCancel() {
62
-
const requestUri = getRequestUri()
63
-
if (requestUri) {
64
-
navigate(routes.oauthLogin, { params: { request_uri: requestUri } })
65
-
} else {
66
-
window.history.back()
67
-
}
68
-
}
69
-
70
-
let isBackupCode = $derived(code.trim().length === 8 && /^[A-Z0-9]+$/i.test(code.trim()))
71
-
let isTotpCode = $derived(code.trim().length === 6 && /^[0-9]+$/.test(code.trim()))
72
-
let canSubmit = $derived(isBackupCode || isTotpCode)
73
-
</script>
74
-
75
-
<div class="oauth-totp-container">
76
-
<h1>{$_('oauth.totp.title')}</h1>
77
-
78
-
{#if error}
79
-
<div class="error">{error}</div>
80
-
{/if}
81
-
82
-
<form onsubmit={handleSubmit}>
83
-
<div>
84
-
<label for="code">{$_('oauth.totp.codePlaceholder')}</label>
85
-
<input
86
-
id="code"
87
-
type="text"
88
-
bind:value={code}
89
-
placeholder={isBackupCode ? $_('oauth.totp.backupCodePlaceholder') : $_('oauth.totp.codePlaceholder')}
90
-
disabled={submitting}
91
-
required
92
-
maxlength="8"
93
-
autocomplete="one-time-code"
94
-
autocapitalize="characters"
95
-
/>
96
-
{#if isBackupCode || isTotpCode}
97
-
<p class="hint">
98
-
{isBackupCode ? $_('oauth.totp.hintBackupCode') : $_('oauth.totp.hintTotpCode')}
99
-
</p>
100
-
{/if}
101
-
</div>
102
-
103
-
<label class="trust-device-label">
104
-
<input
105
-
type="checkbox"
106
-
bind:checked={trustDevice}
107
-
disabled={submitting}
108
-
/>
109
-
<span>{$_('oauth.totp.trustDevice')}</span>
110
-
</label>
111
-
112
-
<div class="actions">
113
-
<button type="button" class="cancel" onclick={handleCancel} disabled={submitting}>
114
-
{$_('common.cancel')}
115
-
</button>
116
-
<button type="submit" disabled={submitting || !canSubmit}>
117
-
{submitting ? $_('common.verifying') : $_('common.verify')}
118
-
</button>
119
-
</div>
120
-
</form>
121
-
</div>
-27
frontend/src/routes/RegisterPasskey.svelte
-27
frontend/src/routes/RegisterPasskey.svelte
···
1
-
<script lang="ts">
2
-
import { startOAuthRegister } from '../lib/oauth'
3
-
import { _ } from '../lib/i18n'
4
-
5
-
let error = $state<string | null>(null)
6
-
let initiated = false
7
-
8
-
$effect(() => {
9
-
if (!initiated) {
10
-
initiated = true
11
-
startOAuthRegister().catch((err) => {
12
-
error = err instanceof Error ? err.message : 'Failed to start registration'
13
-
})
14
-
}
15
-
})
16
-
</script>
17
-
18
-
<div class="register-redirect">
19
-
{#if error}
20
-
<div class="message error">{error}</div>
21
-
<a href="/app/login">{$_('register.signIn')}</a>
22
-
{:else}
23
-
<div class="loading-content">
24
-
<p>{$_('common.loading')}</p>
25
-
</div>
26
-
{/if}
27
-
</div>
History
3 rounds
0 comments
oyster.cafe
submitted
#2
1 commit
expand
collapse
refactor(frontend): simplify API client and delete obsolete auth routes
expand 0 comments
pull request successfully merged
oyster.cafe
submitted
#1
1 commit
expand
collapse
refactor(frontend): simplify API client and delete obsolete auth routes
expand 0 comments
oyster.cafe
submitted
#0
1 commit
expand
collapse
refactor(frontend): simplify API client and delete obsolete auth routes