Use salt instead of device id for email settings
This commit is contained in:
parent
2b2515b1be
commit
42561c8c02
2 changed files with 38 additions and 7 deletions
|
|
@ -4,9 +4,8 @@ import {Address, DELETE, makeEvent, makeHttpAuth, makeHttpAuthHeader} from "@wel
|
|||
import {Relays, User} from "@welshman/app"
|
||||
import {buildUrl} from "@lib/util"
|
||||
import {app, thunks} from "@app/core"
|
||||
import {device} from "@app/device"
|
||||
import {EMAIL_NOTIFICATION_SERVER, PUSH_BRIDGE} from "@app/env"
|
||||
import {userSettingsValues} from "@app/settings"
|
||||
import {ensureEmailSalt, userSettingsValues} from "@app/settings"
|
||||
import {emailNotificationState, syncRelaySubscriptions} from "@app/push/adapters/common"
|
||||
|
||||
export class MailNotifications {
|
||||
|
|
@ -138,8 +137,11 @@ export class MailNotifications {
|
|||
)
|
||||
}
|
||||
|
||||
_getSubscriptionIdentifier = (relay: string, key: string) =>
|
||||
String(hash(relay + key + device.get() + "email"))
|
||||
_getSubscriptionIdentifier = async (relay: string, key: string) => {
|
||||
const salt = await ensureEmailSalt()
|
||||
|
||||
return String(hash(relay + key + salt + "email"))
|
||||
}
|
||||
|
||||
_getPushUrl = async (url: string) => {
|
||||
for (const candidate of [url, PUSH_BRIDGE]) {
|
||||
|
|
@ -161,7 +163,7 @@ export class MailNotifications {
|
|||
return
|
||||
}
|
||||
|
||||
const identifier = this._getSubscriptionIdentifier(relay, key)
|
||||
const identifier = await this._getSubscriptionIdentifier(relay, key)
|
||||
|
||||
const thunk = thunks.get().publish({
|
||||
relays: [url],
|
||||
|
|
@ -188,7 +190,7 @@ export class MailNotifications {
|
|||
if (!url) return
|
||||
|
||||
const $pubkey = User.require(app.get()).pubkey
|
||||
const identifier = this._getSubscriptionIdentifier(relay, key)
|
||||
const identifier = await this._getSubscriptionIdentifier(relay, key)
|
||||
const address = new Address(30390, $pubkey, identifier).toString()
|
||||
const event = makeEvent(DELETE, {tags: [["a", address]]})
|
||||
const error = await thunks
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import {derived, writable} from "svelte/store"
|
||||
import {append, remove, spec} from "@welshman/lib"
|
||||
import {append, call, randomId, remove, spec} from "@welshman/lib"
|
||||
import {APP_DATA} from "@welshman/util"
|
||||
import {withGetter} from "@welshman/store"
|
||||
import {AppData} from "@welshman/domain"
|
||||
|
|
@ -10,6 +10,8 @@ import {app, fromApp, usePlugin} from "@app/core"
|
|||
|
||||
export const SETTINGS = "flotilla/settings"
|
||||
|
||||
const emailSaltsByPubkey = new Map<string, Promise<string>>()
|
||||
|
||||
export enum RelayAuthMode {
|
||||
Aggressive = "aggressive",
|
||||
Conservative = "conservative",
|
||||
|
|
@ -34,6 +36,7 @@ export type SettingsValues = {
|
|||
email: boolean
|
||||
emailAddress: string
|
||||
emailFrequency: string
|
||||
emailSalt: string
|
||||
}
|
||||
|
||||
export const defaultSettings: SettingsValues = {
|
||||
|
|
@ -49,6 +52,7 @@ export const defaultSettings: SettingsValues = {
|
|||
email: false,
|
||||
emailAddress: "",
|
||||
emailFrequency: "daily",
|
||||
emailSalt: "",
|
||||
}
|
||||
|
||||
export class Settings extends DerivedPlugin<AppDataReader> {
|
||||
|
|
@ -121,6 +125,31 @@ export const publishSettings = async (params: Partial<SettingsValues>) => {
|
|||
return command.publish()
|
||||
}
|
||||
|
||||
// A per-account salt for building deterministic identifiers (e.g. kind 30390 email
|
||||
// subscription ids) that reproduce on any device of the user, stored with the settings.
|
||||
export const ensureEmailSalt = () => {
|
||||
const $pubkey = User.require(app.get()).pubkey
|
||||
const existing = emailSaltsByPubkey.get($pubkey)
|
||||
if (existing) return existing
|
||||
|
||||
// Force-load from the network so a salt synced by another device wins over a fresh one,
|
||||
// and memoize the in-flight promise so parallel syncs (one per space relay) share a salt.
|
||||
const promise = call(async () => {
|
||||
await settings.get().forceLoad($pubkey)
|
||||
const salt = userSettingsValues.get().emailSalt
|
||||
if (salt) return salt
|
||||
|
||||
const emailSalt = randomId()
|
||||
await publishSettings({emailSalt})
|
||||
|
||||
return emailSalt
|
||||
})
|
||||
|
||||
emailSaltsByPubkey.set($pubkey, promise)
|
||||
|
||||
return promise
|
||||
}
|
||||
|
||||
export const addTrustedRelay = (url: string) =>
|
||||
publishSettings({trusted_relays: append(url, getSetting("trusted_relays"))})
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue