* Wrapping scripts with xor

* Add function subscribeForErrors to handle errors
This commit is contained in:
Pavel 2021-02-25 18:36:10 +03:00 committed by GitHub
parent 619c8a6d6a
commit c65c0afbee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 122 additions and 24 deletions

View File

@ -10,7 +10,6 @@ import {
} from '../../internal/builtins';
import { ModuleConfig } from '../../internal/moduleConfig';
import { checkConnection } from '../../api';
import log from 'loglevel';
import { generatePeerId } from '../..';
import { FluenceClientImpl } from '../../internal/FluenceClientImpl';
import { createConnectedClient, nodes } from '../connection';

View File

@ -2,9 +2,9 @@ import { encode } from 'bs58';
import { generatePeerId, peerIdToSeed, seedToPeerId } from '../../internal/peerIdUtils';
import { FluenceClientImpl } from '../../internal/FluenceClientImpl';
import log from 'loglevel';
import { createClient } from '../../api';
import { createClient, subscribeForErrors } from '../../api';
import Multiaddr from 'multiaddr';
import { createConnectedClient, nodes } from '../connection';
import { createConnectedClient, createLocalClient, nodes } from '../connection';
describe('Typescript usage suite', () => {
it('should create private key from seed and back', async function () {
@ -219,4 +219,46 @@ describe('Typescript usage suite', () => {
let res = await resMakingPromise;
expect(res).toEqual(['some a', 'some b', 'some c', 'some d']);
});
it('xor handling should work with connected client', async function () {
// arrange
const client = await createConnectedClient(nodes[0].multiaddr);
log.setLevel('info');
// act
let script = `
(seq
(call relay ("op" "identity") [])
(call relay ("incorrect" "service") ["incorrect_arg"])
)
`;
const data = new Map();
data.set('relay', client.relayPeerId);
const promise = subscribeForErrors(client, 7000);
await client.sendScript(script, data);
// assert
await expect(promise).rejects.toMatchObject({
error: expect.stringContaining("Service with id 'incorrect' not found"),
instruction: expect.stringContaining('incorrect'),
});
});
it('xor handling should work with local client', async function () {
// arrange
const client = await createLocalClient();
// act
let script = `(call %init_peer_id% ("incorrect" "service") ["incorrect_arg"])`;
const promise = subscribeForErrors(client, 7000);
await client.sendScript(script);
// assert
await expect(promise).rejects.toMatchObject({
error: expect.stringContaining('There is no service: incorrect'),
instruction: expect.stringContaining('incorrect'),
});
});
});

View File

@ -45,27 +45,39 @@ describe('== AIR suite', () => {
});
it('call broken script', async function () {
// arrange
const client = await createLocalClient();
const script = `(incorrect)`;
const script = `(htyth)`;
// act
const promise = client.sendScript(script);
await expect(client.sendScript(script)).rejects.toContain("aqua script can't be parsed");
// assert
await expect(promise).rejects.toContain("aqua script can't be parsed");
});
it('call script without ttl', async function () {
// arrange
const client = await createLocalClient();
const script = `(call %init_peer_id% ("" "") [""])`;
await expect(client.sendScript(script, undefined, 1)).rejects.toContain('Particle expired');
// act
const promise = client.sendScript(script, undefined, 1);
// assert
await expect(promise).rejects.toContain('Particle expired');
});
it.skip('call broken script by fetch', async function () {
// arrange
const client = await createLocalClient();
const script = `(incorrect)`;
const script = `(htyth)`;
// act
const promise = client.fetch(script, ['result']);
await expect(client.fetch(script, ['result'])).rejects.toContain("aqua script can't be parsed");
// assert
await expect(promise).rejects.toContain("aqua script can't be parsed");
});
it('check particle arguments', async function () {

View File

@ -190,3 +190,25 @@ export const checkConnection = async (client: FluenceClient): Promise<boolean> =
return false;
}
};
export const subscribeForErrors = (client: FluenceClient, ttl: number): Promise<void> => {
return new Promise((resolve, reject) => {
registerServiceFunction(client, '__magic', 'handle_xor', (args, _) => {
setTimeout(() => {
try {
reject(JSON.parse(args[0]));
} catch {
reject(args);
}
}, 0);
unregisterServiceFunction(client, '__magic', 'handle_xor');
return {};
});
setTimeout(() => {
unregisterServiceFunction(client, '__magic', 'handle_xor');
resolve();
}, ttl);
});
};

View File

@ -26,7 +26,7 @@ import { PeerIdB58 } from './commonTypes';
export abstract class FluenceClientBase {
readonly selfPeerIdFull: PeerId;
get relayPeerId(): PeerIdB58 {
get relayPeerId(): PeerIdB58 | undefined {
return this.connection?.nodePeerId.toB58String();
}
@ -88,7 +88,7 @@ export abstract class FluenceClientBase {
}
async sendScript(script: string, data?: Map<string, any>, ttl?: number): Promise<string> {
const particle = await build(this.selfPeerIdFull, script, data, ttl);
const particle = await build(this.selfPeerIdFull, this.relayPeerId, script, data, ttl);
await this.processor.executeLocalParticle(particle);
return particle.id;
}

View File

@ -71,7 +71,7 @@ export class FluenceClientImpl extends FluenceClientBase implements FluenceClien
data = this.addRelayToArgs(data);
const callBackId = genUUID();
script = wrapFetchCall(script, callBackId, resultArgNames);
const particle = await build(this.selfPeerIdFull, script, data, ttl, callBackId);
const particle = await build(this.selfPeerIdFull, this.relayPeerId, script, data, ttl, callBackId);
const prFetch = new Promise<T>(async (resolve, reject) => {
this.fetchParticles.set(callBackId, { resolve, reject });

View File

@ -77,23 +77,17 @@ export class ParticleProcessor {
// TODO: destroy interpreter
}
async executeLocalParticle(particle: ParticleDto) {
async executeLocalParticle(particle: ParticleDto): Promise<void> {
this.strategy?.onLocalParticleRecieved(particle);
return new Promise<void>((resolve, reject) => {
const resolveCallback = function () {
resolve();
};
const rejectCallback = function (err: any) {
reject(err);
};
// we check by callbacks that the script passed through the interpreter without errors
this.handleParticle(particle, resolveCallback, rejectCallback);
this.handleParticle(particle, resolve, reject);
});
}
async executeExternalParticle(particle: ParticleDto) {
async executeExternalParticle(particle: ParticleDto): Promise<void> {
this.strategy?.onExternalParticleRecieved(particle);
await this.handleExternalParticle(particle);
return await this.handleExternalParticle(particle);
}
/*
@ -231,7 +225,7 @@ export class ParticleProcessor {
if (nextParticle) {
// update current particle
this.setCurrentParticleId(nextParticle.id);
await this.handleParticle(nextParticle);
return await this.handleParticle(nextParticle);
} else {
// wait for a new call (do nothing) if there is no new particle in a queue
this.setCurrentParticleId(undefined);
@ -249,7 +243,7 @@ export class ParticleProcessor {
if (error !== undefined) {
log.error('error in external particle: ', error);
} else {
await this.handleParticle(particle);
return await this.handleParticle(particle);
}
}

View File

@ -19,6 +19,7 @@ import { fromByteArray, toByteArray } from 'base64-js';
import PeerId from 'peer-id';
import { encode } from 'bs58';
import { injectDataIntoParticle } from './ParticleProcessor';
import { PeerIdB58 } from './commonTypes';
const DEFAULT_TTL = 7000;
@ -91,8 +92,28 @@ function wrapWithVariableInjectionScript(script: string, fields: string[]): stri
return script;
}
function wrapWithXor(script: string): string {
return `
(xor
${script}
(seq
(call __magic_relay ("op" "identity") [])
(call %init_peer_id% ("__magic" "handle_xor") [%last_error%])
)
)`;
}
function wrapWithXorLocal(script: string): string {
return `
(xor
${script}
(call %init_peer_id% ("__magic" "handle_xor") [%last_error%])
)`;
}
export async function build(
peerId: PeerId,
relay: PeerIdB58 | undefined,
script: string,
data?: Map<string, any>,
ttl?: number,
@ -109,8 +130,16 @@ export async function build(
ttl = DEFAULT_TTL;
}
if (relay) {
data.set('__magic_relay', relay);
}
injectDataIntoParticle(id, data, ttl);
script = wrapWithVariableInjectionScript(script, Array.from(data.keys()));
if (relay) {
script = wrapWithXor(script);
} else {
script = wrapWithXorLocal(script);
}
let particle: ParticleDto = {
id: id,