Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: added group verification proof changes and shifted session key logic to Push Nodes #826

Merged
merged 1 commit into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/restapi/src/lib/chat/addAdmins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const addAdmins = async (
}

const upsertPayload = {
members: [],
admins: admins,
};

Expand Down
3 changes: 2 additions & 1 deletion packages/restapi/src/lib/chat/addMembers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export interface AddMembersToGroupType extends EnvOptionsType {
members: Array<string>;
account?: string | null;
signer?: SignerType | null;
pgpPrivateKey?: string | null;
pgpPrivateKey?: string | null;
}

/**
Expand Down Expand Up @@ -35,6 +35,7 @@ export const addMembers = async (

const upsertPayload = {
members: members,
admins: [],
};

const groupMemberUpdateOptions: GroupMemberUpdateOptions = {
Expand Down
5 changes: 0 additions & 5 deletions packages/restapi/src/lib/chat/approveRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ export const approveCore = async (
? await getUserDID(senderAddress, env)
: await getUserDID(address, env);

let sessionKey: string | null = null;
let encryptedSecret: string | null = null;
/**
* GENERATE VERIFICATION PROOF
Expand All @@ -103,8 +102,6 @@ export const approveCore = async (
plainText: secretKey,
keys: publicKeys,
});

sessionKey = CryptoJS.SHA256(encryptedSecret).toString();
}
}

Expand All @@ -130,7 +127,6 @@ export const approveCore = async (
fromDID,
toDID,
status,
sessionKey: sessionKey,
encryptedSecret: encryptedSecret,
};
break;
Expand All @@ -151,7 +147,6 @@ export const approveCore = async (
status,
sigType,
verificationProof,
sessionKey,
encryptedSecret,
};

Expand Down
222 changes: 222 additions & 0 deletions packages/restapi/src/lib/chat/createGroupV2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
import axios from 'axios';
import { getAPIBaseUrls, isValidETHAddress } from '../helpers';
import Constants from '../constants';
import { EnvOptionsType, GroupDTO, SignerType, Rules } from '../types';
import {
getWallet,
getUserDID,
IPGPHelper,
PGPHelper,
validateScheduleDates,
getConnectedUserV2Core,
} from './helpers';
import * as CryptoJS from 'crypto-js';

export interface ChatCreateGroupTypeV2 extends EnvOptionsType {
account?: string | null;
signer?: SignerType | null;
pgpPrivateKey?: string | null;
// Profile
groupName: string;
groupDescription: string | null;
groupImage: string | null;
rules: Rules | null;
isPublic: boolean;
groupType: 'default' | 'space';
config: {
meta: string | null;
scheduleAt: Date | null;
scheduleEnd: Date | null;
status: 'PENDING' | null;
};
members: Array<string>;
admins: Array<string>;
}

export const createGroupV2 = async (options: ChatCreateGroupTypeV2) => {
return await createGroupCoreV2(options, PGPHelper);
};

export const createGroupCoreV2 = async (
options: ChatCreateGroupTypeV2,
pgpHelper: IPGPHelper
): Promise<GroupDTO> => {
const {
account = null,
signer = null,
pgpPrivateKey = null,
env = Constants.ENV.PROD,
groupName,
groupDescription,
groupImage,
rules,
isPublic,
groupType,
config: { meta, scheduleAt, scheduleEnd, status },
members,
admins,
} = options;

try {
const wallet = getWallet({ account, signer });
const connectedUser = await getConnectedUserV2Core(
wallet,
pgpPrivateKey,
env,
pgpHelper
);
const convertedMembersPromise = members.map(async (each) => {
return getUserDID(each, env);
});
const convertedAdminsPromise = admins.map(async (each) => {
return getUserDID(each, env);
});
const convertedMembers = await Promise.all(convertedMembersPromise);
const convertedAdmins = await Promise.all(convertedAdminsPromise);
/**
* VALIDATIONS
*/
createGroupV2OptionsValidator(options);
/**
* PROFILE VERIFICATION PROOF
*/
const profileVerificationBody = {
groupName,
groupDescription,
groupImage,
rules,
isPublic,
groupType,
};
const profileHash = CryptoJS.SHA256(
JSON.stringify(profileVerificationBody)
).toString();
const profileSignature: string = await pgpHelper.sign({
message: profileHash,
signingKey: connectedUser.privateKey!,
});
const profileVerificationProof = `pgpv2:${profileSignature}:${connectedUser.did}`;
/**
* CONFIG VERIFICATION PROOF
*/
const configVerificationBody = {
meta,
scheduleAt,
scheduleEnd,
status,
};
const configHash = CryptoJS.SHA256(
JSON.stringify(configVerificationBody)
).toString();
const configSignature: string = await pgpHelper.sign({
message: configHash,
signingKey: connectedUser.privateKey!,
});
const configVerificationProof = `pgpv2:${configSignature}:${connectedUser.did}`;
/**
* IDEMPOTENT VERIFICATION PROOF
*/
const idempotentVerificationBody = {
members: convertedMembers,
admins: convertedAdmins,
};
const idempotentHash = CryptoJS.SHA256(
JSON.stringify(idempotentVerificationBody)
).toString();
const idempotentSignature: string = await pgpHelper.sign({
message: idempotentHash,
signingKey: connectedUser.privateKey!,
});
const idempotentVerificationProof = `pgpv2:${idempotentSignature}:${connectedUser.did}`;

const API_BASE_URL = getAPIBaseUrls(env);
const apiEndpoint = `${API_BASE_URL}/v2/chat/groups`;
const body = {
groupName,
groupDescription,
groupImage,
rules,
isPublic,
groupType,
profileVerificationProof,
config: {
meta,
scheduleAt,
scheduleEnd,
status,
configVerificationProof,
},
members: convertedMembers,
admins: convertedAdmins,
idempotentVerificationProof,
};

return axios
.post(apiEndpoint, body)
.then((response) => {
return response.data;
})
.catch((err) => {
if (err?.response?.data)
throw new Error(JSON.stringify(err?.response?.data));
throw new Error(err);
});
} catch (err) {
console.error(
`[Push SDK] - API - Error - API ${createGroupV2.name} -: `,
err
);
throw Error(
`[Push SDK] - API - Error - API ${createGroupV2.name} -: ${err}`
);
}
};

const createGroupV2OptionsValidator = (
options: ChatCreateGroupTypeV2
): void => {
const {
account = null,
signer = null,
pgpPrivateKey = null,
groupName,
groupDescription,
groupImage,
rules,
isPublic,
groupType,
config: { meta, scheduleAt, scheduleEnd, status },
members,
admins,
} = options;

if (!pgpPrivateKey && !signer) {
throw new Error(`At least one from pgpPrivateKey or signer is necessary!`);
}

if (groupName == null || groupName.length == 0) {
throw new Error(`groupName cannot be null or empty`);
}

if (groupName.length > 50) {
throw new Error(`groupName cannot be more than 50 characters`);
}

if (groupDescription && groupDescription.length > 150) {
throw new Error(`groupDescription cannot be more than 150 characters`);
}

for (let i = 0; i < members.length; i++) {
if (members[i] && !isValidETHAddress(members[i])) {
throw new Error(`Invalid member address!`);
}
}

for (let i = 0; i < admins.length; i++) {
if (!isValidETHAddress(admins[i])) {
throw new Error(`Invalid admin address!`);
}
}

validateScheduleDates(scheduleAt, scheduleEnd);
};
3 changes: 0 additions & 3 deletions packages/restapi/src/lib/chat/helpers/payloadHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ export interface IUpdateGroupRequestPayload {
admins: Array<string>;
address: string;
verificationProof: string;
sessionKey: string | null;
encryptedSecret: string | null;
}

Expand Down Expand Up @@ -365,7 +364,6 @@ export const updateGroupPayload = (
admins: Array<string>,
address: string,
verificationProof: string,
sessionKey: string | null,
encryptedSecret: string | null,
groupDescription?: string | null,
groupImage?: string | null,
Expand All @@ -383,7 +381,6 @@ export const updateGroupPayload = (
admins: admins,
address: address,
verificationProof: verificationProof,
sessionKey: sessionKey,
encryptedSecret: encryptedSecret,
scheduleAt: scheduleAt,
scheduleEnd: scheduleEnd,
Expand Down
10 changes: 5 additions & 5 deletions packages/restapi/src/lib/chat/helpers/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export const updateGroupRequestValidator = (
export const validateGroupMemberUpdateOptions = (
options: GroupMemberUpdateOptions
): void => {
const { chatId, upsert, remove, } = options;
const { chatId, upsert, remove } = options;

if (!chatId || chatId.trim().length === 0) {
throw new Error('Chat ID cannot be null or empty.');
Expand All @@ -227,8 +227,8 @@ export const validateGroupMemberUpdateOptions = (
`Invalid role: ${role}. Allowed roles are ${allowedRoles.join(', ')}.`
);
}
if (upsert[role] && upsert[role].length > 1000) {
throw new Error(`${role} array cannot have more than 1000 addresses.`);
if (upsert[role] && upsert[role].length > 100) {
throw new Error(`${role} array cannot have more than 100 addresses.`);
}
// Assuming you have a function `isValidETHAddress` to validate Ethereum addresses
upsert[role].forEach((address) => {
Expand All @@ -239,8 +239,8 @@ export const validateGroupMemberUpdateOptions = (
});

// Validating remove array
if (remove && remove.length > 1000) {
throw new Error('Remove array cannot have more than 1000 addresses.');
if (remove && remove.length > 100) {
throw new Error('Remove array cannot have more than 100 addresses.');
}
remove.forEach((address) => {
if (!isValidETHAddress(address)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/restapi/src/lib/chat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export { decryptPGPKey } from '../helpers/crypto';
export { decryptConversation } from './helpers';
export * from './helpers/payloadHelper';
export * from './createGroup';
export * from './createGroupV2';
export * from './updateGroup';
export * from './getGroup';
export * from './getGroupByName';
Expand All @@ -25,4 +26,3 @@ export * from './getGroupMemberStatus';
export * from './getGroupMembers';
export * from './getGroupInfo';
export * from './getChatMemberCount';
;
5 changes: 4 additions & 1 deletion packages/restapi/src/lib/chat/removeAdmins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ export const removeAdmins = async (

const groupMemberUpdateOptions: GroupMemberUpdateOptions = {
chatId: chatId,
upsert: {},
upsert: {
members: [],
admins: [],
},
remove: admins,
account: account,
signer: signer,
Expand Down
5 changes: 4 additions & 1 deletion packages/restapi/src/lib/chat/removeMembers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ export const removeMembers = async (

const groupMemberUpdateOptions: GroupMemberUpdateOptions = {
chatId: chatId,
upsert: {},
upsert: {
members: [],
admins: [],
},
remove: members,
account: account,
signer: signer,
Expand Down
Loading
Loading