diff --git a/apps/mobile-app/hooks/useVaultMutate.ts b/apps/mobile-app/hooks/useVaultMutate.ts index c7fd21011..07f000dfa 100644 --- a/apps/mobile-app/hooks/useVaultMutate.ts +++ b/apps/mobile-app/hooks/useVaultMutate.ts @@ -55,12 +55,17 @@ export function useVaultMutate() : { setSyncStatus('Uploading vault to server'); - // Get email addresses from credentials + // Get all private email domains from credentials in order to claim them on server + const privateEmailDomains = await dbContext.sqliteClient!.getPrivateEmailDomains(); + const credentials = await dbContext.sqliteClient!.getAllCredentials(); - const emailAddresses = credentials + const privateEmailAddresses = credentials .filter(cred => cred.Alias?.Email != null) .map(cred => cred.Alias!.Email!) - .filter((email, index, self) => self.indexOf(email) === index); + .filter((email, index, self) => self.indexOf(email) === index) + .filter(email => { + return privateEmailDomains.some(domain => email.toLowerCase().endsWith(`@${domain.toLowerCase()}`)); + }); // Get username from the auth context const username = authContext.username; @@ -74,7 +79,7 @@ export function useVaultMutate() : { createdAt: new Date().toISOString(), credentialsCount: credentials.length, currentRevisionNumber: currentRevision, - emailAddressList: emailAddresses, + emailAddressList: privateEmailAddresses, privateEmailDomainList: [], // Empty on purpose, API will not use this for vault updates publicEmailDomainList: [], // Empty on purpose, API will not use this for vault updates encryptionPublicKey: '', // Empty on purpose, only required if new public/private key pair is generated diff --git a/apps/mobile-app/utils/SqliteClient.tsx b/apps/mobile-app/utils/SqliteClient.tsx index 111e3c047..655b03c98 100644 --- a/apps/mobile-app/utils/SqliteClient.tsx +++ b/apps/mobile-app/utils/SqliteClient.tsx @@ -112,6 +112,15 @@ class SqliteClient { } } + /** + * Get the private email domains supported by the AliasVault server from the vault metadata. + * @returns The private email domains. + */ + public async getPrivateEmailDomains(): Promise { + const metadata = await this.getVaultMetadata(); + return metadata?.privateEmailDomains ?? []; + } + /** * Store the encryption key in the native keychain */ diff --git a/apps/server/AliasVault.Api/Controllers/VaultController.cs b/apps/server/AliasVault.Api/Controllers/VaultController.cs index 5140df4d5..94356109f 100644 --- a/apps/server/AliasVault.Api/Controllers/VaultController.cs +++ b/apps/server/AliasVault.Api/Controllers/VaultController.cs @@ -411,6 +411,9 @@ public class VaultController(ILogger logger, IAliasServerDbCont // Keep track of processed and sanitized email addresses to know which ones still exist. var processedEmailAddresses = new List(); + // Get list of supported private domains from config + var supportedPrivateDomains = config.PrivateEmailDomains; + // Register new email addresses. foreach (var email in newEmailAddresses) { @@ -421,6 +424,17 @@ public class VaultController(ILogger logger, IAliasServerDbCont // If email address is invalid according to the EmailAddressAttribute, skip it. if (!new EmailAddressAttribute().IsValid(sanitizedEmail)) { + logger.LogWarning("{User} tried to claim invalid email address: {Email}", user.UserName, sanitizedEmail); + continue; + } + + // Extract domain from email + var domain = sanitizedEmail.Split('@')[1]; + + // Skip if domain is not in supported private domains list + if (!supportedPrivateDomains.Contains(domain)) + { + logger.LogWarning("{User} tried to claim email with unsupported private domain: {Email}", user.UserName, sanitizedEmail); continue; }