mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 21:45:31 +09:00
feat(auth): add username sign-in mode and recovery kits (#3215)
This commit is contained in:
1 parent
bf3d73a5f7
commit
e1eecc3b6c
355 files changed
+52138
-24097
No files matched your search
@@ -196,6 +196,7 @@ export async function initializeWorkerDependencies(snowflakeService: ISnowflakeS
|
||||
const instanceConfigRepository = getInstanceConfigRepository();
|
||||
const limitConfigService = getLimitConfigService();
|
||||
await instanceConfigRepository.initialize();
|
||||
await instanceConfigRepository.ensureAccountIdentityMode();
|
||||
await limitConfigService.initialize();
|
||||
limitConfigService.setAsGlobalInstance();
|
||||
const userCacheService = createUserCacheService();
|
||||
|
||||
@@ -71,34 +71,51 @@ describe('harvestMessages', () => {
|
||||
});
|
||||
});
|
||||
|
||||
function userDataParams(overrides: Partial<Parameters<typeof buildUserDataJson>[0]> = {}) {
|
||||
return {
|
||||
user: new User({...EMPTY_USER_ROW, user_id: AUTHOR, username: 'exporter', discriminator: 1}),
|
||||
userId: AUTHOR,
|
||||
productName: 'Fluxer',
|
||||
authSessions: [],
|
||||
relationships: [],
|
||||
userNotes: new Map(),
|
||||
userSettings: null,
|
||||
guildMemberships: [],
|
||||
guildSettings: [],
|
||||
savedMessages: [],
|
||||
privateChannels: [],
|
||||
favoriteMemes: [],
|
||||
pushSubscriptions: [],
|
||||
webAuthnCredentials: [],
|
||||
mfaBackupCodes: [],
|
||||
recoveryKitCreatedAt: null,
|
||||
createdGiftCodes: [],
|
||||
payments: [],
|
||||
storePurchases: [],
|
||||
oauthClients: [],
|
||||
connections: [],
|
||||
pinnedDms: [],
|
||||
authorizedIps: [],
|
||||
activityData: {last_active_at: null, last_active_ip: null},
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe('buildUserDataJson', () => {
|
||||
it('exports the store purchases in their public shape', () => {
|
||||
const purchase = buildStorePurchaseRow({user_id: AUTHOR});
|
||||
const data = buildUserDataJson({
|
||||
user: new User({...EMPTY_USER_ROW, user_id: AUTHOR, username: 'exporter', discriminator: 1}),
|
||||
userId: AUTHOR,
|
||||
productName: 'Fluxer',
|
||||
authSessions: [],
|
||||
relationships: [],
|
||||
userNotes: new Map(),
|
||||
userSettings: null,
|
||||
guildMemberships: [],
|
||||
guildSettings: [],
|
||||
savedMessages: [],
|
||||
privateChannels: [],
|
||||
favoriteMemes: [],
|
||||
pushSubscriptions: [],
|
||||
webAuthnCredentials: [],
|
||||
mfaBackupCodes: [],
|
||||
createdGiftCodes: [],
|
||||
payments: [],
|
||||
storePurchases: [purchase],
|
||||
oauthClients: [],
|
||||
connections: [],
|
||||
pinnedDms: [],
|
||||
authorizedIps: [],
|
||||
activityData: {last_active_at: null, last_active_ip: null},
|
||||
});
|
||||
const data = buildUserDataJson(userDataParams({storePurchases: [purchase]}));
|
||||
expect(data.store_purchases).toEqual([mapStorePurchaseToResponse(purchase)]);
|
||||
});
|
||||
|
||||
it('exports when the recovery kit was created and nothing else about it', () => {
|
||||
const createdAt = new Date('2026-10-01T12:00:00.000Z');
|
||||
const data = buildUserDataJson(userDataParams({recoveryKitCreatedAt: createdAt}));
|
||||
expect(data.recovery_kit).toEqual({created_at: '2026-10-01T12:00:00.000Z'});
|
||||
});
|
||||
|
||||
it('leaves the recovery kit out when the account has none', () => {
|
||||
const data = buildUserDataJson(userDataParams());
|
||||
expect('recovery_kit' in data).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
throwIfArchiveTerminallyFailed,
|
||||
} from '@app/api/archive/ArchiveTask';
|
||||
import {makeDataPackageAttachmentCdnUrl} from '@app/api/attachment/AttachmentUrls';
|
||||
import {findRecoveryKitCreatedAt} from '@app/api/auth/AuthRecoveryKit';
|
||||
import {
|
||||
type ChannelID,
|
||||
createAttachmentID,
|
||||
@@ -132,6 +133,7 @@ interface UserDataJsonParams {
|
||||
pushSubscriptions: Array<PushSubscription>;
|
||||
webAuthnCredentials: Array<WebAuthnCredential>;
|
||||
mfaBackupCodes: Array<MfaBackupCode>;
|
||||
recoveryKitCreatedAt: Date | null;
|
||||
createdGiftCodes: Array<GiftCode>;
|
||||
payments: Array<Payment>;
|
||||
storePurchases: Array<StorePurchaseRow>;
|
||||
@@ -427,6 +429,7 @@ export function buildUserDataJson(params: UserDataJsonParams) {
|
||||
pushSubscriptions,
|
||||
webAuthnCredentials,
|
||||
mfaBackupCodes,
|
||||
recoveryKitCreatedAt,
|
||||
createdGiftCodes,
|
||||
payments,
|
||||
storePurchases,
|
||||
@@ -622,6 +625,7 @@ export function buildUserDataJson(params: UserDataJsonParams) {
|
||||
consumed_count: mfaBackupCodes.filter((code) => code.consumed).length,
|
||||
remaining_count: mfaBackupCodes.filter((code) => !code.consumed).length,
|
||||
},
|
||||
...(recoveryKitCreatedAt ? {recovery_kit: {created_at: recoveryKitCreatedAt.toISOString()}} : {}),
|
||||
gift_codes_created: createdGiftCodes.map((gift) => ({
|
||||
code: gift.code,
|
||||
duration_months: gift.durationMonths,
|
||||
@@ -849,6 +853,7 @@ const harvestUserData: ArchiveTaskHandler = async (payload, helpers, attempt) =>
|
||||
pushSubscriptions,
|
||||
webAuthnCredentials,
|
||||
mfaBackupCodes,
|
||||
recoveryKitCreatedAt,
|
||||
createdGiftCodes,
|
||||
payments,
|
||||
storePurchases,
|
||||
@@ -869,6 +874,7 @@ const harvestUserData: ArchiveTaskHandler = async (payload, helpers, attempt) =>
|
||||
userRepository.listPushSubscriptions(userId),
|
||||
userRepository.listWebAuthnCredentials(userId),
|
||||
userRepository.listMfaBackupCodes(userId),
|
||||
findRecoveryKitCreatedAt(userId),
|
||||
userRepository.findGiftCodesByCreator(userId),
|
||||
paymentRepository.findPaymentsByUserId(userId),
|
||||
storeEntitlementService.listStorePurchases(userId),
|
||||
@@ -905,6 +911,7 @@ const harvestUserData: ArchiveTaskHandler = async (payload, helpers, attempt) =>
|
||||
pushSubscriptions,
|
||||
webAuthnCredentials,
|
||||
mfaBackupCodes,
|
||||
recoveryKitCreatedAt,
|
||||
createdGiftCodes,
|
||||
payments,
|
||||
storePurchases,
|
||||
|
||||
Reference in new issue
Block a user