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: refactor isLocalMessage to generalize use cases #32

Merged
merged 14 commits into from
Oct 5, 2023
Merged
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"react/react-in-jsx-scope": "off",
"react/jsx-uses-react": "off",
"simple-import-sort/imports": "error",
"react/jsx-sort-props": "warn"
"react/jsx-sort-props": "warn",
"react/prop-types": "off"
},
"overrides": [
{
Expand Down
45 changes: 45 additions & 0 deletions .github/workflows/pr-ci-healchecks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: PR CI Health checks

on:
pull_request:
branches: [ main ]

defaults:
run:
working-directory: ./

jobs:
health-checks:
runs-on: ubuntu-latest
strategy:
fail-fast: true
max-parallel: 1
matrix:
target: ['lint', 'build', 'test']

steps:
- name: Check out repository
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Use nx set shas
uses: nrwl/nx-set-shas@v3


- name: Setup Node version
uses: actions/setup-node@v3
with:
node-version: 18
check-latest: false
registry-url: https://registry.npmjs.org
cache: "npm"
cache-dependency-path: package-lock.json

- name: Install dependencies
run: |
npm cache verify
npm ci --no-audit --prefer-offline

- name: Run NX target ${{ matrix.target }} on affected projects
run: npx nx affected -t ${{ matrix.target }} --parallel=3 --skip-nx-cache --verbose
147 changes: 147 additions & 0 deletions libs/shinkai-message-ts/src/utils/shinkai_message_handler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { isLocalMessage } from './shinkai_message_handler';

describe('shinkai_messag_handler isLocalMessage', () => {
const messageSentByNode1MainDevice = `{
"body": {
"unencrypted": {
"message_data": {
"unencrypted": {
"message_raw_content": "hey!",
"message_content_schema": "TextContent"
}
},
"internal_metadata": {
"sender_subidentity": "main/device/main_device",
"recipient_subidentity": "",
"inbox": "inbox::@@node1.shinkai/main/device/main_device::@@node2.shinkai::false",
"signature": "",
"encryption": "None"
}
}
},
"external_metadata": {
"sender": "@@node1.shinkai",
"recipient": "@@node2.shinkai",
"scheduled_time": "2023-08-25T22:44:01.132Z",
"signature": "c6d0115c0878fbf2279f98aab67c0e9cb1af63825f49dca48d6e4420eba0ceb973e00488ba0905c9afd09254f0dac48c468fdcb1d6c5ab5ca4c5dd70a440b903",
"other": ""
},
"encryption": "None",
"version": "V1_0"
}`;

const messageSentByNode1SecondaryDevice = `{
"body": {
"unencrypted": {
"message_data": {
"unencrypted": {
"message_raw_content": "hey!",
"message_content_schema": "TextContent"
}
},
"internal_metadata": {
"sender_subidentity": "main/device/secondary_device",
"recipient_subidentity": "",
"inbox": "inbox::@@node1.shinkai/main/device/secondary_device::@@node2.shinkai::false",
"signature": "",
"encryption": "None"
}
}
},
"external_metadata": {
"sender": "@@node1.shinkai",
"recipient": "@@node2.shinkai",
"scheduled_time": "2023-08-25T22:44:01.132Z",
"signature": "c6d0115c0878fbf2279f98aab67c0e9cb1af63825f49dca48d6e4420eba0ceb973e00488ba0905c9afd09254f0dac48c468fdcb1d6c5ab5ca4c5dd70a440b903",
"other": ""
},
"encryption": "None",
"version": "V1_0"
}`;

const messageSentByNode1AgentGpt = `{
"body": {
"unencrypted": {
"message_data": {
"unencrypted": {
"message_raw_content": "hey!",
"message_content_schema": "TextContent"
}
},
"internal_metadata": {
"sender_subidentity": "main/agent/gpt",
"recipient_subidentity": "",
"inbox": "job_inbox::@@node1.shinkai/main/agent/gpt::@@node2.shinkai::false",
"signature": "",
"encryption": "None"
}
}
},
"external_metadata": {
"sender": "@@node1.shinkai",
"recipient": "@@node2.shinkai",
"scheduled_time": "2023-08-25T22:44:01.132Z",
"signature": "c6d0115c0878fbf2279f98aab67c0e9cb1af63825f49dca48d6e4420eba0ceb973e00488ba0905c9afd09254f0dac48c468fdcb1d6c5ab5ca4c5dd70a440b903",
"other": ""
},
"encryption": "None",
"version": "V1_0"
}`;

const messageSentByNode2MainDevice = `{
"body": {
"unencrypted": {
"message_data": {
"unencrypted": {
"message_raw_content": "hey!",
"message_content_schema": "TextContent"
}
},
"internal_metadata": {
"sender_subidentity": "main/device/main_device",
"recipient_subidentity": "",
"inbox": "inbox::@@node2.shinkai/main/device/main_device::@@node1.shinkai::false",
"signature": "",
"encryption": "None"
}
}
},
"external_metadata": {
"sender": "@@node2.shinkai",
"recipient": "@@node1.shinkai",
"scheduled_time": "2023-08-25T22:44:01.132Z",
"signature": "c6d0115c0878fbf2279f98aab67c0e9cb1af63825f49dca48d6e4420eba0ceb973e00488ba0905c9afd09254f0dac48c468fdcb1d6c5ab5ca4c5dd70a440b903",
"other": ""
},
"encryption": "None",
"version": "V1_0"
}`;

const myNodeSetup = {
myNodeIdentity: '@@node1.shinkai',
myProfile: 'main',
};
it('false when message was sent by agent', () => {
const message = JSON.parse(messageSentByNode1AgentGpt);
const isLocal = isLocalMessage(message, myNodeSetup.myNodeIdentity, myNodeSetup.myProfile);
expect(isLocal).toBe(false);
});

it('false when message was sent by a different node', () => {
const message = JSON.parse(messageSentByNode2MainDevice);
const isLocal = isLocalMessage(message, myNodeSetup.myNodeIdentity, myNodeSetup.myProfile);
expect(isLocal).toBe(false);
});

it('true when message was sent by same node', () => {
const message = JSON.parse(messageSentByNode1MainDevice);
const isLocal = isLocalMessage(message, myNodeSetup.myNodeIdentity, myNodeSetup.myProfile);
expect(isLocal).toBe(true);
});

it('true when message was sent by same node but different device', () => {
const message = JSON.parse(messageSentByNode1SecondaryDevice);
const isLocal = isLocalMessage(message, myNodeSetup.myNodeIdentity, myNodeSetup.myProfile);
expect(isLocal).toBe(true);
});
});
11 changes: 7 additions & 4 deletions libs/shinkai-message-ts/src/utils/shinkai_message_handler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { MessageSchemaType } from '../models/SchemaTypes';
import { ShinkaiMessage } from '../models/ShinkaiMessage';
import { ShinkaiNameWrapper } from '../wasm';
import { ShinkaiMessageWrapper } from '../wasm/ShinkaiMessageWrapper';

export function calculateMessageHash(message: ShinkaiMessage): string {
Expand Down Expand Up @@ -51,8 +52,10 @@ export const getMessageContent = (message: ShinkaiMessage) => {

export const isLocalMessage = (
message: ShinkaiMessage,
identity: string,
profile: string,
) => {
return message.external_metadata?.sender === `${identity}/${profile}`;
myNodeIdentity: string,
myProfile: string,
): boolean => {
const messageNameWrapper = ShinkaiNameWrapper.from_shinkai_message_sender(message);
return (messageNameWrapper.get_subidentity_type === 'None' || messageNameWrapper.get_subidentity_type === 'device') &&
messageNameWrapper.get_node_name === myNodeIdentity && messageNameWrapper.get_profile_name === myProfile;
};
3 changes: 1 addition & 2 deletions libs/shinkai-message-ts/src/utils/wasm_helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ import { sha512 } from '@noble/hashes/sha512';
import { Crypto } from "@peculiar/webcrypto";

import { generateEncryptionKeys, generateSignatureKeys, test_util_generateKeys } from './wasm_helpers';
console.log('PATATATATATATA2');
console.log('PATATATATATATA');console.log('PATATATATATATA');console.log('PATATATATATATA');console.log('PATATATATATATA');console.log('PATATATATATATA');console.log('PATATATATATATA');

// Enable synchronous methods
ed.etc.sha512Sync = (...m) => sha512(ed.etc.concatBytes(...m));

Expand Down
60 changes: 60 additions & 0 deletions libs/shinkai-message-ts/src/wasm/ShinkaiNameWrapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,63 @@ test("ShinkaiNameWrapper get_profile_name", () => {
expect(wrapper.extract_profile().get_full_name).toBe(profile.toLowerCase());
}
});

test("ShinkaiNameWrapper from_shinkai_message_sender", () => {
it('should fail when message is first level encrypted', () => {
const encryptedMessage = `{
"body": {
"encrypted": {
agallardol marked this conversation as resolved.
Show resolved Hide resolved
"content": "encrypted:de9a22018a78cb1977d72936145576a4e040a590c5da6ac9f60f334c5fddd773b53ca11c5a97110e4352a694fa55632e9e07346e60a579171aea11fcf17a8e9666fe8f3bfddadafe5b2ecef5b8d7759979536e8ae848c1976a5057892836d0a5806fdaf4a30220217da2f4930914aea7b1f0f4ae65175ca9d24db4408294ca4b7347048a295ef5eeac1f3a60112953edf3f78bd02103fc9ae866cbb223385781218f0c021e41c79f529b7fd8748d8339db1cc0e03ae7d3b27b6147639cc01f44e594401bea76743ddefff47e737df61710c30fc7e5f38da306336cf668c198dfa2f90506"
}
},
"external_metadata": {
"sender": "@@node1.shinkai/main",
"recipient": "@@node1.shinkai",
"scheduled_time": "2023-10-04T19:38:50.271Z",
"signature": "028810426c653e993deea94aa08b8fec14e82040ba73b09e533726eb769ea5de87ba095cc83cfe35035ca2db1ce996c963b7e7b12b1a28240706e4e0cbef6904",
"other": ""
},
"encryption": "DiffieHellmanChaChaPoly1305",
"version": "V1_0"
}`;
const message = JSON.parse(encryptedMessage);
expect(ShinkaiNameWrapper.from_shinkai_message_sender(message)).toThrowError();
});

it('should parse node_name, full_name, subidentity_name and subidentity_type when message is unepcrypted', () => {
const messageJson = `{
"body": {
"unencrypted": {
"message_data": {
"unencrypted": {
"message_raw_content": "hey!",
"message_content_schema": "TextContent"
}
},
"internal_metadata": {
"sender_subidentity": "main/device/main_device",
"recipient_subidentity": "",
"inbox": "inbox::@@node1.shinkai/main/device/main_device::@@node2.shinkai::false",
"signature": "",
"encryption": "None"
}
}
},
"external_metadata": {
"sender": "@@node1.shinkai",
"recipient": "@@node2.shinkai",
"scheduled_time": "2023-08-25T22:44:01.132Z",
"signature": "c6d0115c0878fbf2279f98aab67c0e9cb1af63825f49dca48d6e4420eba0ceb973e00488ba0905c9afd09254f0dac48c468fdcb1d6c5ab5ca4c5dd70a440b903",
"other": ""
},
"encryption": "None",
"version": "V1_0"
}`;
const message = JSON.parse(messageJson);
const messageNameWrapper = ShinkaiNameWrapper.from_shinkai_message_sender(message);
expect(messageNameWrapper.get_node_name).toBe('@@node1.shinkai');
expect(messageNameWrapper.get_full_name).toBe('@@node1.shinkai/main/device/main_device');
expect(messageNameWrapper.get_subidentity_name).toBe('main/device/main_device');
expect(messageNameWrapper.get_subidentity_type).toBe('device');
});
});
15 changes: 15 additions & 0 deletions libs/shinkai-message-ts/src/wasm/ShinkaiNameWrapper.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ShinkaiMessage } from "../models";
import { ShinkaiNameWrapper as ShinkaiNameWrapperWASM } from "../pkg/shinkai_message_wasm";

export class ShinkaiNameWrapper {
Expand All @@ -7,6 +8,20 @@ export class ShinkaiNameWrapper {
this.wasmWrapper = new ShinkaiNameWrapperWASM(shinkai_name_js);
}

static from_shinkai_message_sender(message: ShinkaiMessage): ShinkaiNameWrapper {
if (message.encryption !== 'None') {
throw new Error('shinkai message is encrypted');
}
if (!message.body || !('unencrypted' in message.body)) {
throw new Error('shinkai message body doesn\'t conestains unencrypted property');
}
let name = message.external_metadata?.sender;
if (message.body.unencrypted.internal_metadata.sender_subidentity) {
name += `/${message.body.unencrypted.internal_metadata.sender_subidentity}`;
}
return new ShinkaiNameWrapper(name);
}

to_jsvalue(): any {
return this.wasmWrapper.to_jsvalue();
}
Expand Down
Loading
Loading