feat: add revoke/unrevoke subrequests

unused currently
pull/2963/head
Audric Ackermann 2 years ago
parent f9502b4bbe
commit 5adfe2e52b

@ -192,10 +192,6 @@ export type UpdateExpireNodeUserParams = WithPubkeyAsString &
export type UpdateExpireNodeGroupParams = WithPubkeyAsGroupPubkey & UpdateExpireAlwaysNeeded;
type UpdateExpiryOnNodeSubRequest =
| UpdateExpiryOnNodeUserSubRequest
| UpdateExpiryOnNodeGroupSubRequest;
export type UpdateExpiryOnNodeUserSubRequest = {
method: 'expire';
params: UpdateExpireNodeUserParams;
@ -206,6 +202,20 @@ export type UpdateExpiryOnNodeGroupSubRequest = {
params: UpdateExpireNodeGroupParams;
};
type UpdateExpiryOnNodeSubRequest =
| UpdateExpiryOnNodeUserSubRequest
| UpdateExpiryOnNodeGroupSubRequest;
export type RevokeSubaccountParams = {
pubkey: GroupPubkeyType;
revoke: string; // the subaccount token to revoke in hex
signature: string;
};
export type RevokeSubaccountSubRequest = {
method: 'revoke_subaccount' | 'unrevoke_subaccount';
params: RevokeSubaccountParams;
};
export type OxendSubRequest = OnsResolveSubRequest | GetServiceNodesSubRequest;
export type SnodeApiSubRequests =
@ -216,7 +226,8 @@ export type SnodeApiSubRequests =
| NetworkTimeSubRequest
| DeleteFromNodeSubRequest
| DeleteAllFromNodeSubRequest
| UpdateExpiryOnNodeSubRequest;
| UpdateExpiryOnNodeSubRequest
| RevokeSubaccountSubRequest;
// eslint-disable-next-line @typescript-eslint/array-type
export type NonEmptyArray<T> = [T, ...T[]];

@ -0,0 +1,84 @@
import { GroupPubkeyType } from 'libsession_util_nodejs';
import _, { isEmpty } from 'lodash';
import { doSnodeBatchRequest } from './batchRequest';
import { UserGroupsWrapperActions } from '../../../webworker/workers/browser/libsession_worker_interface';
import { PubKey } from '../../types';
import { stringToUint8Array } from '../../utils/String';
import { RevokeSubaccountSubRequest } from './SnodeRequestTypes';
import { SnodeGroupSignature } from './signature/groupSignature';
import { getSwarmFor } from './snodePool';
type Change = {
action: 'revoke_subaccount' | 'unrevoke_subaccount';
tokenToRevoke: string;
};
type ArrayOfChange = Array<Change>;
async function getRevokeSubaccountRequest({
groupPk,
actions,
}: {
groupPk: GroupPubkeyType;
actions: ArrayOfChange;
}): Promise<Array<RevokeSubaccountSubRequest>> {
if (!PubKey.isClosedGroupV2(groupPk)) {
throw new Error('revokeSubaccountForGroup: not a 03 group');
}
const group = await UserGroupsWrapperActions.getGroup(groupPk);
if (!group || isEmpty(group?.secretKey)) {
throw new Error(`revokeSubaccountForGroup ${groupPk} needs admin secretkey`);
}
const revokeParams: Array<RevokeSubaccountSubRequest> = await Promise.all(
actions.map(async action => {
const verificationString = `${action}${stringToUint8Array(action.tokenToRevoke)}`;
const sigResult = await SnodeGroupSignature.signDataWithAdminSecret(
verificationString,
group
);
return {
method: action.action,
params: {
revoke: action.tokenToRevoke,
...sigResult,
pubkey: groupPk,
},
};
})
);
return revokeParams;
}
async function revokeSubAccounts(
groupPk: GroupPubkeyType,
actions: ArrayOfChange
): Promise<boolean> {
try {
const swarm = await getSwarmFor(groupPk);
const snode = _.sample(swarm);
if (!snode) {
throw new Error('revoke subaccounts empty swarm');
}
const revokeParams = await getRevokeSubaccountRequest({
groupPk,
actions,
});
const results = await doSnodeBatchRequest(revokeParams, snode, 4000, null);
if (!results || !results.length) {
throw new Error(`_revokeSubAccounts could not talk to ${snode.ip}:${snode.port}`);
}
return true;
} catch (e) {
window?.log?.warn(`_revokeSubAccounts failed with ${e.message}`);
return false;
}
}
export const SnodeAPIRetrieve = { revokeSubAccounts };

@ -154,6 +154,29 @@ async function getSnodeGroupSignature({
throw new Error(`getSnodeGroupSignature: needs either groupSecretKey or authData`);
}
async function signDataWithAdminSecret(
verificationString: string,
group: Pick<GroupDetailsNeededForSignature, 'secretKey'>
) {
const verificationData = StringUtils.encode(verificationString, 'utf8');
const message = new Uint8Array(verificationData);
if (!group) {
throw new Error('signDataWithAdminSecret group was not found');
}
const { secretKey } = group;
const groupSecretKey = secretKey && !isEmpty(secretKey) ? secretKey : null;
if (!groupSecretKey) {
throw new Error('groupSecretKey is empty');
}
const sodium = await getSodiumRenderer();
return {
signature: fromUInt8ArrayToBase64(sodium.crypto_sign_detached(message, groupSecretKey)),
};
}
// this is kind of duplicated with `generateUpdateExpirySignature`, but needs to use the authData when secretKey is not available
async function generateUpdateExpiryGroupSignature({
shortenOrExtend,
@ -214,4 +237,5 @@ export const SnodeGroupSignature = {
generateUpdateExpiryGroupSignature,
getGroupInviteMessage,
getSnodeGroupSignature,
signDataWithAdminSecret,
};

Loading…
Cancel
Save