mirror of
https://github.com/lux-tel/session-desktop.git
synced 2026-10-30 20:33:24 +00:00
209 lines
6.6 KiB
TypeScript
209 lines
6.6 KiB
TypeScript
import { to_hex } from 'libsodium-wrappers-sumo';
|
|
import { PubkeyType } from 'libsession_util_nodejs';
|
|
import _, { isEmpty, isString } from 'lodash';
|
|
import { UserUtils } from '.';
|
|
import { Data } from '../../data/data';
|
|
import { SessionKeyPair } from '../../receiver/keypairs';
|
|
import { getOurPubKeyStrFromStorage } from '../../util/storage';
|
|
import { PubKey } from '../types';
|
|
import { toHex } from './String';
|
|
import { ProWrapperActions } from '../../webworker/workers/browser/libsession_worker_interface';
|
|
import { OutgoingUserProfile } from '../../types/message';
|
|
import { SettingsKey } from '../../data/settings-key';
|
|
import { OutgoingProMessageDetails } from '../../types/message/OutgoingProMessageDetails';
|
|
import { getFeatureFlag } from '../../state/ducks/types/releasedFeaturesReduxTypes';
|
|
import {
|
|
getCachedUserConfig,
|
|
UserConfigWrapperActions,
|
|
} from '../../webworker/workers/browser/libsession/libsession_worker_userconfig_interface';
|
|
|
|
export type HexKeyPair = {
|
|
pubKey: string;
|
|
privKey: string;
|
|
};
|
|
|
|
export type ByteKeyPair = {
|
|
pubKeyBytes: Uint8Array;
|
|
privKeyBytes: Uint8Array;
|
|
};
|
|
|
|
/**
|
|
* Check if this pubkey is us, using the cache.
|
|
* This does not check for us blinded. To check for us or us blinded, use isUsAnySogsFromCache()
|
|
* Throws an error if our pubkey is not set
|
|
*/
|
|
export function isUsFromCache(pubKey: string | PubKey | undefined): boolean {
|
|
if (!pubKey) {
|
|
throw new Error('pubKey is not set');
|
|
}
|
|
const ourNumber = UserUtils.getOurPubKeyStrFromCache();
|
|
const pubKeyStr = pubKey instanceof PubKey ? pubKey.key : pubKey;
|
|
return pubKeyStr === ourNumber;
|
|
}
|
|
|
|
/**
|
|
* Returns the public key of this current device as a STRING, or throws an error
|
|
*/
|
|
export function getOurPubKeyStrFromCache(): PubkeyType {
|
|
const ourNumber = getOurPubKeyStrFromStorage();
|
|
if (!ourNumber) {
|
|
throw new Error('ourNumber is not set');
|
|
}
|
|
|
|
return ourNumber as PubkeyType;
|
|
}
|
|
|
|
/**
|
|
* Returns the public key of this current device as a PubKey, or throws an error
|
|
*/
|
|
export function getOurPubKeyFromCache(): PubKey {
|
|
const ourNumber = UserUtils.getOurPubKeyStrFromCache();
|
|
if (!ourNumber) {
|
|
throw new Error('ourNumber is not set');
|
|
}
|
|
return PubKey.cast(ourNumber);
|
|
}
|
|
|
|
let cachedIdentityKeyPair: SessionKeyPair | undefined;
|
|
|
|
/**
|
|
* This return the stored x25519 identity keypair for the current logged in user
|
|
*/
|
|
export async function getIdentityKeyPair(): Promise<SessionKeyPair | undefined> {
|
|
if (cachedIdentityKeyPair) {
|
|
return cachedIdentityKeyPair;
|
|
}
|
|
const item = await Data.getItemById(SettingsKey.identityKey);
|
|
|
|
cachedIdentityKeyPair = item?.value;
|
|
return cachedIdentityKeyPair;
|
|
}
|
|
|
|
export async function getUserED25519KeyPair(): Promise<HexKeyPair> {
|
|
const ed25519KeyPairBytes = await getUserED25519KeyPairBytes();
|
|
if (!ed25519KeyPairBytes) {
|
|
throw new Error('getUserED25519KeyPair: user has no keypair');
|
|
}
|
|
const { pubKeyBytes, privKeyBytes } = ed25519KeyPairBytes;
|
|
return {
|
|
pubKey: toHex(pubKeyBytes),
|
|
privKey: toHex(privKeyBytes),
|
|
};
|
|
}
|
|
|
|
export const getUserED25519KeyPairBytes = async (): Promise<ByteKeyPair> => {
|
|
// 'identityKey' keeps the ed25519KeyPair under a ed25519KeyPair field.
|
|
// it is only set if the user migrated to the ed25519 way of generating a key
|
|
const item = await UserUtils.getIdentityKeyPair();
|
|
const ed25519KeyPair = (item as any)?.ed25519KeyPair;
|
|
if (ed25519KeyPair?.publicKey && ed25519KeyPair?.privateKey) {
|
|
const pubKeyBytes = new Uint8Array(_.map(ed25519KeyPair.publicKey, a => a));
|
|
const privKeyBytes = new Uint8Array(_.map(ed25519KeyPair.privateKey, a => a));
|
|
return {
|
|
pubKeyBytes,
|
|
privKeyBytes,
|
|
};
|
|
}
|
|
throw new Error('getUserED25519KeyPairBytes: user has no keypair');
|
|
};
|
|
|
|
/**
|
|
* Return the ed25519 seed of the current user. (32 bytes)
|
|
* This is used to generate deterministic encryption keys for attachments/profile pictures.
|
|
*
|
|
* This is cached so will only be slow on the first fetch.
|
|
*/
|
|
export async function getUserEd25519Seed() {
|
|
return (await getUserEd25519PrivKey()).slice(0, 32);
|
|
}
|
|
|
|
async function getUserEd25519PrivKey() {
|
|
const ed25519KeyPairBytes = await getUserED25519KeyPairBytes();
|
|
return ed25519KeyPairBytes.privKeyBytes;
|
|
}
|
|
|
|
export async function getOurProfile() {
|
|
const [displayName, updatedAtSeconds, profilePic] = await Promise.all([
|
|
UserConfigWrapperActions.getName(),
|
|
UserConfigWrapperActions.getProfileUpdatedSeconds(),
|
|
UserConfigWrapperActions.getProfilePic(),
|
|
]);
|
|
|
|
return new OutgoingUserProfile({
|
|
displayName: displayName || 'Anonymous',
|
|
updatedAtSeconds,
|
|
profilePic: profilePic ?? null,
|
|
});
|
|
}
|
|
|
|
export async function getOutgoingProMessageDetails({
|
|
utf16,
|
|
}: {
|
|
utf16: string | null | undefined;
|
|
}) {
|
|
if (!getFeatureFlag('proAvailable')) {
|
|
return null;
|
|
}
|
|
const [proConfig, proProfileBitset] = await Promise.all([
|
|
UserConfigWrapperActions.getProConfig(),
|
|
UserConfigWrapperActions.getProProfileBitset(),
|
|
]);
|
|
|
|
// Note: if we do not have a proof we don't want to send a proMessage.
|
|
// Note: if we don't have a user pro feature enabled, we might still need to add one for the message itself, see below
|
|
if (!proConfig || isEmpty(proConfig?.proProof)) {
|
|
return null;
|
|
}
|
|
|
|
const { proMessageBitset, status } = await ProWrapperActions.proFeaturesForMessage({
|
|
utf16: utf16 ?? '',
|
|
});
|
|
|
|
if (status !== 'SUCCESS') {
|
|
return null;
|
|
}
|
|
return new OutgoingProMessageDetails({
|
|
proConfig,
|
|
proMessageBitset,
|
|
proProfileBitset,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Return the pro master key hex from the Item table, or generate and saves it before returning it.
|
|
*/
|
|
export async function getProMasterKeyHex() {
|
|
const item = await Data.getItemById(SettingsKey.proMasterKeyHex);
|
|
if (!item?.value && isString(item?.value) && item.value.length) {
|
|
return item.value;
|
|
}
|
|
const seedHex = to_hex(await UserUtils.getUserEd25519Seed());
|
|
const { proMasterKeyHex } = await UserConfigWrapperActions.generateProMasterKey({
|
|
ed25519SeedHex: seedHex,
|
|
});
|
|
if (!proMasterKeyHex) {
|
|
throw new Error('Failed to generate pro master key');
|
|
}
|
|
await Data.createOrUpdateItem({
|
|
id: SettingsKey.proMasterKeyHex,
|
|
value: proMasterKeyHex,
|
|
});
|
|
return proMasterKeyHex;
|
|
}
|
|
|
|
/**
|
|
* Return the pro rotating private key (hex) from user config, or generate it before returning it.
|
|
*/
|
|
export async function getProRotatingPrivateKeyHex() {
|
|
const proConfig = getCachedUserConfig().proConfig;
|
|
if (proConfig?.rotatingPrivKeyHex) {
|
|
return proConfig.rotatingPrivKeyHex;
|
|
}
|
|
|
|
const { rotatingPrivKeyHex } = await UserConfigWrapperActions.generateRotatingPrivKeyHex();
|
|
if (!rotatingPrivKeyHex) {
|
|
throw new Error('Failed to generate pro rotating private key');
|
|
}
|
|
return rotatingPrivKeyHex;
|
|
}
|