Tools/specify-clearon-conditions (#8596)
* Specify user clear events for event upload * Specify generator clear events * Specify clear events for user send data * Specify generic clear on logout for encrypted secret state * Allow `clearOn`event to be passed into secret state * Match current data persistence rules * Clear ui memory on lock + logout
This commit is contained in:
parent
759e48728e
commit
1308b326fd
|
@ -8,7 +8,7 @@ export { ActiveUserState, SingleUserState, CombinedState } from "./user-state";
|
||||||
export { ActiveUserStateProvider, SingleUserStateProvider } from "./user-state.provider";
|
export { ActiveUserStateProvider, SingleUserStateProvider } from "./user-state.provider";
|
||||||
export { KeyDefinition, KeyDefinitionOptions } from "./key-definition";
|
export { KeyDefinition, KeyDefinitionOptions } from "./key-definition";
|
||||||
export { StateUpdateOptions } from "./state-update-options";
|
export { StateUpdateOptions } from "./state-update-options";
|
||||||
export { UserKeyDefinition } from "./user-key-definition";
|
export { UserKeyDefinitionOptions, UserKeyDefinition } from "./user-key-definition";
|
||||||
export { StateEventRunnerService } from "./state-event-runner.service";
|
export { StateEventRunnerService } from "./state-event-runner.service";
|
||||||
|
|
||||||
export * from "./state-definitions";
|
export * from "./state-definitions";
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { StateDefinition } from "./state-definition";
|
||||||
|
|
||||||
export type ClearEvent = "lock" | "logout";
|
export type ClearEvent = "lock" | "logout";
|
||||||
|
|
||||||
type UserKeyDefinitionOptions<T> = KeyDefinitionOptions<T> & {
|
export type UserKeyDefinitionOptions<T> = KeyDefinitionOptions<T> & {
|
||||||
clearOn: ClearEvent[];
|
clearOn: ClearEvent[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { EventData } from "../../models/data/event.data";
|
import { EventData } from "../../models/data/event.data";
|
||||||
import { KeyDefinition, EVENT_COLLECTION_DISK } from "../../platform/state";
|
import { EVENT_COLLECTION_DISK, UserKeyDefinition } from "../../platform/state";
|
||||||
|
|
||||||
export const EVENT_COLLECTION: KeyDefinition<EventData[]> = KeyDefinition.array<EventData>(
|
export const EVENT_COLLECTION = UserKeyDefinition.array<EventData>(
|
||||||
EVENT_COLLECTION_DISK,
|
EVENT_COLLECTION_DISK,
|
||||||
"events",
|
"events",
|
||||||
{
|
{
|
||||||
deserializer: (s) => EventData.fromJSON(s),
|
deserializer: (s) => EventData.fromJSON(s),
|
||||||
|
clearOn: ["logout"],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { GENERATOR_DISK, GENERATOR_MEMORY, KeyDefinition } from "../../platform/state";
|
import { GENERATOR_DISK, GENERATOR_MEMORY, UserKeyDefinition } from "../../platform/state";
|
||||||
|
|
||||||
import { GeneratedCredential } from "./history/generated-credential";
|
import { GeneratedCredential } from "./history/generated-credential";
|
||||||
import { GeneratorNavigation } from "./navigation/generator-navigation";
|
import { GeneratorNavigation } from "./navigation/generator-navigation";
|
||||||
|
@ -17,110 +17,122 @@ import {
|
||||||
import { SubaddressGenerationOptions } from "./username/subaddress-generator-options";
|
import { SubaddressGenerationOptions } from "./username/subaddress-generator-options";
|
||||||
|
|
||||||
/** plaintext password generation options */
|
/** plaintext password generation options */
|
||||||
export const GENERATOR_SETTINGS = new KeyDefinition<GeneratorNavigation>(
|
export const GENERATOR_SETTINGS = new UserKeyDefinition<GeneratorNavigation>(
|
||||||
GENERATOR_MEMORY,
|
GENERATOR_MEMORY,
|
||||||
"generatorSettings",
|
"generatorSettings",
|
||||||
{
|
{
|
||||||
deserializer: (value) => value,
|
deserializer: (value) => value,
|
||||||
|
clearOn: ["lock", "logout"],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/** plaintext password generation options */
|
/** plaintext password generation options */
|
||||||
export const PASSWORD_SETTINGS = new KeyDefinition<PasswordGenerationOptions>(
|
export const PASSWORD_SETTINGS = new UserKeyDefinition<PasswordGenerationOptions>(
|
||||||
GENERATOR_DISK,
|
GENERATOR_DISK,
|
||||||
"passwordGeneratorSettings",
|
"passwordGeneratorSettings",
|
||||||
{
|
{
|
||||||
deserializer: (value) => value,
|
deserializer: (value) => value,
|
||||||
|
clearOn: [],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/** plaintext passphrase generation options */
|
/** plaintext passphrase generation options */
|
||||||
export const PASSPHRASE_SETTINGS = new KeyDefinition<PassphraseGenerationOptions>(
|
export const PASSPHRASE_SETTINGS = new UserKeyDefinition<PassphraseGenerationOptions>(
|
||||||
GENERATOR_DISK,
|
GENERATOR_DISK,
|
||||||
"passphraseGeneratorSettings",
|
"passphraseGeneratorSettings",
|
||||||
{
|
{
|
||||||
deserializer: (value) => value,
|
deserializer: (value) => value,
|
||||||
|
clearOn: [],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/** plaintext username generation options */
|
/** plaintext username generation options */
|
||||||
export const EFF_USERNAME_SETTINGS = new KeyDefinition<EffUsernameGenerationOptions>(
|
export const EFF_USERNAME_SETTINGS = new UserKeyDefinition<EffUsernameGenerationOptions>(
|
||||||
GENERATOR_DISK,
|
GENERATOR_DISK,
|
||||||
"effUsernameGeneratorSettings",
|
"effUsernameGeneratorSettings",
|
||||||
{
|
{
|
||||||
deserializer: (value) => value,
|
deserializer: (value) => value,
|
||||||
|
clearOn: [],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/** plaintext configuration for a domain catch-all address. */
|
/** plaintext configuration for a domain catch-all address. */
|
||||||
export const CATCHALL_SETTINGS = new KeyDefinition<CatchallGenerationOptions>(
|
export const CATCHALL_SETTINGS = new UserKeyDefinition<CatchallGenerationOptions>(
|
||||||
GENERATOR_DISK,
|
GENERATOR_DISK,
|
||||||
"catchallGeneratorSettings",
|
"catchallGeneratorSettings",
|
||||||
{
|
{
|
||||||
deserializer: (value) => value,
|
deserializer: (value) => value,
|
||||||
|
clearOn: [],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/** plaintext configuration for an email subaddress. */
|
/** plaintext configuration for an email subaddress. */
|
||||||
export const SUBADDRESS_SETTINGS = new KeyDefinition<SubaddressGenerationOptions>(
|
export const SUBADDRESS_SETTINGS = new UserKeyDefinition<SubaddressGenerationOptions>(
|
||||||
GENERATOR_DISK,
|
GENERATOR_DISK,
|
||||||
"subaddressGeneratorSettings",
|
"subaddressGeneratorSettings",
|
||||||
{
|
{
|
||||||
deserializer: (value) => value,
|
deserializer: (value) => value,
|
||||||
|
clearOn: [],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/** backing store configuration for {@link Forwarders.AddyIo} */
|
/** backing store configuration for {@link Forwarders.AddyIo} */
|
||||||
export const ADDY_IO_FORWARDER = new KeyDefinition<SelfHostedApiOptions & EmailDomainOptions>(
|
export const ADDY_IO_FORWARDER = new UserKeyDefinition<SelfHostedApiOptions & EmailDomainOptions>(
|
||||||
GENERATOR_DISK,
|
GENERATOR_DISK,
|
||||||
"addyIoForwarder",
|
"addyIoForwarder",
|
||||||
{
|
{
|
||||||
deserializer: (value) => value,
|
deserializer: (value) => value,
|
||||||
|
clearOn: [],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/** backing store configuration for {@link Forwarders.DuckDuckGo} */
|
/** backing store configuration for {@link Forwarders.DuckDuckGo} */
|
||||||
export const DUCK_DUCK_GO_FORWARDER = new KeyDefinition<ApiOptions>(
|
export const DUCK_DUCK_GO_FORWARDER = new UserKeyDefinition<ApiOptions>(
|
||||||
GENERATOR_DISK,
|
GENERATOR_DISK,
|
||||||
"duckDuckGoForwarder",
|
"duckDuckGoForwarder",
|
||||||
{
|
{
|
||||||
deserializer: (value) => value,
|
deserializer: (value) => value,
|
||||||
|
clearOn: [],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/** backing store configuration for {@link Forwarders.FastMail} */
|
/** backing store configuration for {@link Forwarders.FastMail} */
|
||||||
export const FASTMAIL_FORWARDER = new KeyDefinition<ApiOptions & EmailPrefixOptions>(
|
export const FASTMAIL_FORWARDER = new UserKeyDefinition<ApiOptions & EmailPrefixOptions>(
|
||||||
GENERATOR_DISK,
|
GENERATOR_DISK,
|
||||||
"fastmailForwarder",
|
"fastmailForwarder",
|
||||||
{
|
{
|
||||||
deserializer: (value) => value,
|
deserializer: (value) => value,
|
||||||
|
clearOn: [],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/** backing store configuration for {@link Forwarders.FireFoxRelay} */
|
/** backing store configuration for {@link Forwarders.FireFoxRelay} */
|
||||||
export const FIREFOX_RELAY_FORWARDER = new KeyDefinition<ApiOptions>(
|
export const FIREFOX_RELAY_FORWARDER = new UserKeyDefinition<ApiOptions>(
|
||||||
GENERATOR_DISK,
|
GENERATOR_DISK,
|
||||||
"firefoxRelayForwarder",
|
"firefoxRelayForwarder",
|
||||||
{
|
{
|
||||||
deserializer: (value) => value,
|
deserializer: (value) => value,
|
||||||
|
clearOn: [],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/** backing store configuration for {@link Forwarders.ForwardEmail} */
|
/** backing store configuration for {@link Forwarders.ForwardEmail} */
|
||||||
export const FORWARD_EMAIL_FORWARDER = new KeyDefinition<ApiOptions & EmailDomainOptions>(
|
export const FORWARD_EMAIL_FORWARDER = new UserKeyDefinition<ApiOptions & EmailDomainOptions>(
|
||||||
GENERATOR_DISK,
|
GENERATOR_DISK,
|
||||||
"forwardEmailForwarder",
|
"forwardEmailForwarder",
|
||||||
{
|
{
|
||||||
deserializer: (value) => value,
|
deserializer: (value) => value,
|
||||||
|
clearOn: [],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
/** backing store configuration for {@link forwarders.SimpleLogin} */
|
/** backing store configuration for {@link forwarders.SimpleLogin} */
|
||||||
export const SIMPLE_LOGIN_FORWARDER = new KeyDefinition<SelfHostedApiOptions>(
|
export const SIMPLE_LOGIN_FORWARDER = new UserKeyDefinition<SelfHostedApiOptions>(
|
||||||
GENERATOR_DISK,
|
GENERATOR_DISK,
|
||||||
"simpleLoginForwarder",
|
"simpleLoginForwarder",
|
||||||
{
|
{
|
||||||
deserializer: (value) => value,
|
deserializer: (value) => value,
|
||||||
|
clearOn: [],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -131,5 +143,6 @@ export const GENERATOR_HISTORY = SecretKeyDefinition.array(
|
||||||
SecretClassifier.allSecret<GeneratedCredential>(),
|
SecretClassifier.allSecret<GeneratedCredential>(),
|
||||||
{
|
{
|
||||||
deserializer: GeneratedCredential.fromJSON,
|
deserializer: GeneratedCredential.fromJSON,
|
||||||
|
clearOn: ["logout"],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
import { GENERATOR_DISK } from "../../../platform/state";
|
import { GENERATOR_DISK, UserKeyDefinitionOptions } from "../../../platform/state";
|
||||||
|
|
||||||
import { SecretClassifier } from "./secret-classifier";
|
import { SecretClassifier } from "./secret-classifier";
|
||||||
import { SecretKeyDefinition } from "./secret-key-definition";
|
import { SecretKeyDefinition } from "./secret-key-definition";
|
||||||
|
|
||||||
describe("SecretKeyDefinition", () => {
|
describe("SecretKeyDefinition", () => {
|
||||||
const classifier = SecretClassifier.allSecret<{ foo: boolean }>();
|
const classifier = SecretClassifier.allSecret<{ foo: boolean }>();
|
||||||
const options = { deserializer: (v: any) => v };
|
const options: UserKeyDefinitionOptions<any> = { deserializer: (v: any) => v, clearOn: [] };
|
||||||
|
|
||||||
it("toEncryptedStateKey returns a key", () => {
|
it("toEncryptedStateKey returns a key", () => {
|
||||||
const expectedOptions = {
|
const expectedOptions: UserKeyDefinitionOptions<any> = {
|
||||||
deserializer: (v: any) => v,
|
deserializer: (v: any) => v,
|
||||||
cleanupDelayMs: 100,
|
cleanupDelayMs: 100,
|
||||||
|
clearOn: ["logout", "lock"],
|
||||||
};
|
};
|
||||||
const definition = SecretKeyDefinition.value(
|
const definition = SecretKeyDefinition.value(
|
||||||
GENERATOR_DISK,
|
GENERATOR_DISK,
|
||||||
|
@ -26,6 +27,7 @@ describe("SecretKeyDefinition", () => {
|
||||||
expect(result.stateDefinition).toEqual(GENERATOR_DISK);
|
expect(result.stateDefinition).toEqual(GENERATOR_DISK);
|
||||||
expect(result.key).toBe("key");
|
expect(result.key).toBe("key");
|
||||||
expect(result.cleanupDelayMs).toBe(expectedOptions.cleanupDelayMs);
|
expect(result.cleanupDelayMs).toBe(expectedOptions.cleanupDelayMs);
|
||||||
|
expect(result.clearOn).toEqual(expectedOptions.clearOn);
|
||||||
expect(deserializerResult).toBe(expectedDeserializerResult);
|
expect(deserializerResult).toBe(expectedDeserializerResult);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { KeyDefinition, KeyDefinitionOptions } from "../../../platform/state";
|
import { UserKeyDefinitionOptions, UserKeyDefinition } from "../../../platform/state";
|
||||||
// eslint-disable-next-line -- `StateDefinition` used as an argument
|
// eslint-disable-next-line -- `StateDefinition` used as an argument
|
||||||
import { StateDefinition } from "../../../platform/state/state-definition";
|
import { StateDefinition } from "../../../platform/state/state-definition";
|
||||||
import { ClassifiedFormat } from "./classified-format";
|
import { ClassifiedFormat } from "./classified-format";
|
||||||
|
@ -11,7 +11,7 @@ export class SecretKeyDefinition<Outer, Id, Inner extends object, Disclosed, Sec
|
||||||
readonly stateDefinition: StateDefinition,
|
readonly stateDefinition: StateDefinition,
|
||||||
readonly key: string,
|
readonly key: string,
|
||||||
readonly classifier: SecretClassifier<Inner, Disclosed, Secret>,
|
readonly classifier: SecretClassifier<Inner, Disclosed, Secret>,
|
||||||
readonly options: KeyDefinitionOptions<Inner>,
|
readonly options: UserKeyDefinitionOptions<Inner>,
|
||||||
// type erasure is necessary here because typescript doesn't support
|
// type erasure is necessary here because typescript doesn't support
|
||||||
// higher kinded types that generalize over collections. The invariants
|
// higher kinded types that generalize over collections. The invariants
|
||||||
// needed to make this typesafe are maintained by the static factories.
|
// needed to make this typesafe are maintained by the static factories.
|
||||||
|
@ -21,12 +21,14 @@ export class SecretKeyDefinition<Outer, Id, Inner extends object, Disclosed, Sec
|
||||||
|
|
||||||
/** Converts the secret key to the `KeyDefinition` used for secret storage. */
|
/** Converts the secret key to the `KeyDefinition` used for secret storage. */
|
||||||
toEncryptedStateKey() {
|
toEncryptedStateKey() {
|
||||||
const secretKey = new KeyDefinition<ClassifiedFormat<Id, Disclosed>[]>(
|
const secretKey = new UserKeyDefinition<ClassifiedFormat<Id, Disclosed>[]>(
|
||||||
this.stateDefinition,
|
this.stateDefinition,
|
||||||
this.key,
|
this.key,
|
||||||
{
|
{
|
||||||
cleanupDelayMs: this.options.cleanupDelayMs,
|
cleanupDelayMs: this.options.cleanupDelayMs,
|
||||||
deserializer: (jsonValue) => jsonValue as ClassifiedFormat<Id, Disclosed>[],
|
deserializer: (jsonValue) => jsonValue as ClassifiedFormat<Id, Disclosed>[],
|
||||||
|
// Clear encrypted state on logout
|
||||||
|
clearOn: this.options.clearOn,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -45,7 +47,7 @@ export class SecretKeyDefinition<Outer, Id, Inner extends object, Disclosed, Sec
|
||||||
stateDefinition: StateDefinition,
|
stateDefinition: StateDefinition,
|
||||||
key: string,
|
key: string,
|
||||||
classifier: SecretClassifier<Value, Disclosed, Secret>,
|
classifier: SecretClassifier<Value, Disclosed, Secret>,
|
||||||
options: KeyDefinitionOptions<Value>,
|
options: UserKeyDefinitionOptions<Value>,
|
||||||
) {
|
) {
|
||||||
return new SecretKeyDefinition<Value, void, Value, Disclosed, Secret>(
|
return new SecretKeyDefinition<Value, void, Value, Disclosed, Secret>(
|
||||||
stateDefinition,
|
stateDefinition,
|
||||||
|
@ -69,7 +71,7 @@ export class SecretKeyDefinition<Outer, Id, Inner extends object, Disclosed, Sec
|
||||||
stateDefinition: StateDefinition,
|
stateDefinition: StateDefinition,
|
||||||
key: string,
|
key: string,
|
||||||
classifier: SecretClassifier<Item, Disclosed, Secret>,
|
classifier: SecretClassifier<Item, Disclosed, Secret>,
|
||||||
options: KeyDefinitionOptions<Item>,
|
options: UserKeyDefinitionOptions<Item>,
|
||||||
) {
|
) {
|
||||||
return new SecretKeyDefinition<Item[], number, Item, Disclosed, Secret>(
|
return new SecretKeyDefinition<Item[], number, Item, Disclosed, Secret>(
|
||||||
stateDefinition,
|
stateDefinition,
|
||||||
|
@ -93,7 +95,7 @@ export class SecretKeyDefinition<Outer, Id, Inner extends object, Disclosed, Sec
|
||||||
stateDefinition: StateDefinition,
|
stateDefinition: StateDefinition,
|
||||||
key: string,
|
key: string,
|
||||||
classifier: SecretClassifier<Item, Disclosed, Secret>,
|
classifier: SecretClassifier<Item, Disclosed, Secret>,
|
||||||
options: KeyDefinitionOptions<Item>,
|
options: UserKeyDefinitionOptions<Item>,
|
||||||
) {
|
) {
|
||||||
return new SecretKeyDefinition<Record<Id, Item>, Id, Item, Disclosed, Secret>(
|
return new SecretKeyDefinition<Record<Id, Item>, Id, Item, Disclosed, Secret>(
|
||||||
stateDefinition,
|
stateDefinition,
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { Observable, map, pipe } from "rxjs";
|
||||||
import { PolicyType } from "../../../admin-console/enums";
|
import { PolicyType } from "../../../admin-console/enums";
|
||||||
import { CryptoService } from "../../../platform/abstractions/crypto.service";
|
import { CryptoService } from "../../../platform/abstractions/crypto.service";
|
||||||
import { EncryptService } from "../../../platform/abstractions/encrypt.service";
|
import { EncryptService } from "../../../platform/abstractions/encrypt.service";
|
||||||
import { KeyDefinition, SingleUserState, StateProvider } from "../../../platform/state";
|
import { SingleUserState, StateProvider, UserKeyDefinition } from "../../../platform/state";
|
||||||
import { UserId } from "../../../types/guid";
|
import { UserId } from "../../../types/guid";
|
||||||
import { GeneratorStrategy } from "../abstractions";
|
import { GeneratorStrategy } from "../abstractions";
|
||||||
import { DefaultPolicyEvaluator } from "../default-policy-evaluator";
|
import { DefaultPolicyEvaluator } from "../default-policy-evaluator";
|
||||||
|
@ -56,6 +56,7 @@ export abstract class ForwarderGeneratorStrategy<
|
||||||
const key = SecretKeyDefinition.value(this.key.stateDefinition, this.key.key, classifier, {
|
const key = SecretKeyDefinition.value(this.key.stateDefinition, this.key.key, classifier, {
|
||||||
deserializer: (d) => this.key.deserializer(d),
|
deserializer: (d) => this.key.deserializer(d),
|
||||||
cleanupDelayMs: this.key.cleanupDelayMs,
|
cleanupDelayMs: this.key.cleanupDelayMs,
|
||||||
|
clearOn: this.key.clearOn,
|
||||||
});
|
});
|
||||||
|
|
||||||
// the type parameter is explicit because type inference fails for `Omit<Options, "website">`
|
// the type parameter is explicit because type inference fails for `Omit<Options, "website">`
|
||||||
|
@ -83,7 +84,7 @@ export abstract class ForwarderGeneratorStrategy<
|
||||||
abstract defaults$: (userId: UserId) => Observable<Options>;
|
abstract defaults$: (userId: UserId) => Observable<Options>;
|
||||||
|
|
||||||
/** Determine where forwarder configuration is stored */
|
/** Determine where forwarder configuration is stored */
|
||||||
protected abstract readonly key: KeyDefinition<Options>;
|
protected abstract readonly key: UserKeyDefinition<Options>;
|
||||||
|
|
||||||
/** {@link GeneratorStrategy.toEvaluator} */
|
/** {@link GeneratorStrategy.toEvaluator} */
|
||||||
toEvaluator = () => {
|
toEvaluator = () => {
|
||||||
|
|
|
@ -1,13 +1,23 @@
|
||||||
import { KeyDefinition, SEND_DISK, SEND_MEMORY } from "../../../platform/state";
|
import { SEND_DISK, SEND_MEMORY, UserKeyDefinition } from "../../../platform/state";
|
||||||
import { SendData } from "../models/data/send.data";
|
import { SendData } from "../models/data/send.data";
|
||||||
import { SendView } from "../models/view/send.view";
|
import { SendView } from "../models/view/send.view";
|
||||||
|
|
||||||
/** Encrypted send state stored on disk */
|
/** Encrypted send state stored on disk */
|
||||||
export const SEND_USER_ENCRYPTED = KeyDefinition.record<SendData>(SEND_DISK, "sendUserEncrypted", {
|
export const SEND_USER_ENCRYPTED = UserKeyDefinition.record<SendData>(
|
||||||
deserializer: (obj: SendData) => obj,
|
SEND_DISK,
|
||||||
});
|
"sendUserEncrypted",
|
||||||
|
{
|
||||||
|
deserializer: (obj: SendData) => obj,
|
||||||
|
clearOn: ["logout"],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
/** Decrypted send state stored in memory */
|
/** Decrypted send state stored in memory */
|
||||||
export const SEND_USER_DECRYPTED = new KeyDefinition<SendView[]>(SEND_MEMORY, "sendUserDecrypted", {
|
export const SEND_USER_DECRYPTED = new UserKeyDefinition<SendView[]>(
|
||||||
deserializer: (obj) => obj,
|
SEND_MEMORY,
|
||||||
});
|
"sendUserDecrypted",
|
||||||
|
{
|
||||||
|
deserializer: (obj) => obj,
|
||||||
|
clearOn: ["lock"],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
Loading…
Reference in New Issue