Skip to content

Commit

Permalink
Issue objects as custom facts
Browse files Browse the repository at this point in the history
  • Loading branch information
adriacidre committed Jun 27, 2024
1 parent 6f13788 commit 952d50a
Show file tree
Hide file tree
Showing 10 changed files with 303 additions and 24 deletions.
26 changes: 13 additions & 13 deletions _examples/document_sign/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
};
exports.__esModule = true;
var self_sdk_1 = require("../../src/self-sdk");
var process_1 = require("process");
var fs_1 = require("fs");
var groups = {};
// Wait til the response is received
Expand All @@ -60,7 +61,7 @@ function setupSDK(appID, appSecret) {
return [4 /*yield*/, self_sdk_1["default"].build(appID, appSecret, "random", storageFolder, opts)];
case 1:
sdk = _a.sent();
return [4 /*yield*/, sdk.messaging().permitConnection("*")];
return [4 /*yield*/, sdk.start()];
case 2:
_a.sent();
return [2 /*return*/, sdk];
Expand All @@ -70,7 +71,7 @@ function setupSDK(appID, appSecret) {
}
function main() {
return __awaiter(this, void 0, void 0, function () {
var appID, appSecret, selfID, sdk, terms, docs, content, resp, i;
var appID, appSecret, selfID, sdk, terms, content, docs, resp, i;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
Expand All @@ -81,28 +82,27 @@ function main() {
case 1:
sdk = _a.sent();
terms = "please, read and accept terms and conditions";
docs = [];
content = fs_1.readFileSync("./sample.pdf").toString('utf8');
docs.push({
name: "Terms and conditions",
data: content,
mime: "application/pdf"
});
content = fs_1.readFileSync("./sample.pdf", null);
docs = [{
name: "Terms and conditions",
data: content,
mime: "application/pdf"
}];
return [4 /*yield*/, sdk.docs().requestSignature(selfID, terms, docs)];
case 2:
resp = _a.sent();
if (resp["status"] == "accepted") {
console.log("Document signed!");
console.log("");
console.log("signned documents: ");
for (i = 0; i < resp["signed_objects"].length; i++) {
console.log("- Name : " + resp["signed_objects"]["name"]);
console.log(" Link : " + resp["signed_objects"]["link"]);
console.log(" Hash : " + resp["signed_objects"]["hash"]);
console.log("- Name : " + resp["signed_objects"][0]["name"]);
console.log(" Link : " + resp["signed_objects"][0]["link"]);
console.log(" Hash : " + resp["signed_objects"][0]["hash"]);
}
console.log("");
console.log("full signature");
console.log(resp["input"]);
process_1.exit(0);
}
return [2 /*return*/];
}
Expand Down
3 changes: 1 addition & 2 deletions _examples/document_sign/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ async function main() {
const sdk = await setupSDK(appID, appSecret)
let terms = "please, read and accept terms and conditions"

var myArrayBuffer = readFileSync("./sample.pdf", null).buffer;
var content = new Uint8Array(myArrayBuffer);
var content = readFileSync("./sample.pdf", null);

let docs = [{
name: "Terms and conditions",
Expand Down
142 changes: 142 additions & 0 deletions _examples/fact_request/custom-objects.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
"use strict";
// Copyright 2020 Self Group Ltd. All Rights Reserved.
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
var self_sdk_1 = require("../../src/self-sdk");
var process_1 = require("process");
var facts_service_1 = require("../../src/facts-service");
var fs_1 = require("fs");
function delay(ms) {
return new Promise(function (resolve) { return setTimeout(resolve, ms); });
}
function request(appID, appSecret, selfID) {
return __awaiter(this, void 0, void 0, function () {
var opts, storageFolder, sdk, source, content, obj, fact, res, at, o, error_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
opts = { 'logLevel': 'debug' };
if (process.env["SELF_ENV"] != "") {
opts['env'] = process.env["SELF_ENV"];
}
storageFolder = __dirname.split("/").slice(0, -1).join("/") + "/.self_storage";
return [4 /*yield*/, self_sdk_1["default"].build(appID, appSecret, "random", storageFolder, opts)];
case 1:
sdk = _a.sent();
return [4 /*yield*/, sdk.start()];
case 2:
_a.sent();
source = "supu";
content = fs_1.readFileSync("./my_image.png");
return [4 /*yield*/, sdk.newObject("test", content, "image/png")
// obj.save("./my_image_copy.jpg")
];
case 3:
obj = _a.sent();
fact = new facts_service_1.FactToIssue("image", obj, source);
sdk.logger.info("fact created");
sdk.logger.info("issuing fact");
return [4 /*yield*/, sdk.facts().issue(selfID, [fact])];
case 4:
_a.sent();
return [4 /*yield*/, delay(10000)];
case 5:
_a.sent();
sdk.logger.info("sending a fact request (" + fact.key + ") to " + selfID);
sdk.logger.info("waiting for user input");
_a.label = 6;
case 6:
_a.trys.push([6, 14, , 15]);
return [4 /*yield*/, sdk.facts().request(selfID, [{
fact: fact.key,
issuers: [appID]
}])];
case 7:
res = _a.sent();
if (!!res) return [3 /*break*/, 8];
sdk.logger.warn("fact request has timed out");
return [3 /*break*/, 13];
case 8:
if (!(res.status === 'accepted')) return [3 /*break*/, 12];
at = res.attestation(fact.key);
if (!(at != null)) return [3 /*break*/, 10];
sdk.logger.info(selfID + " digest is \"" + at.value + "\"");
return [4 /*yield*/, res.object(at.value)];
case 9:
o = _a.sent();
o.save("./received.png");
sdk.logger.info("result stored at /tmp/received.png");
return [3 /*break*/, 11];
case 10:
sdk.logger.warn("No attestations have been returned");
_a.label = 11;
case 11: return [3 /*break*/, 13];
case 12:
sdk.logger.warn(selfID + " has rejected your authentication request");
_a.label = 13;
case 13: return [3 /*break*/, 15];
case 14:
error_1 = _a.sent();
sdk.logger.error(error_1.toString());
return [3 /*break*/, 15];
case 15:
sdk.close();
process_1.exit();
return [2 /*return*/];
}
});
});
}
function main() {
return __awaiter(this, void 0, void 0, function () {
var appID, appSecret, selfID;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
appID = process.env["SELF_APP_ID"];
appSecret = process.env["SELF_APP_SECRET"];
selfID = process.env["SELF_USER_ID"];
return [4 /*yield*/, request(appID, appSecret, selfID)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
}
main();
79 changes: 79 additions & 0 deletions _examples/fact_request/custom-objects.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright 2020 Self Group Ltd. All Rights Reserved.

import SelfSDK from '../../src/self-sdk'
import { exit } from 'process';
import { FactToIssue, Group } from '../../src/facts-service';
import { readFileSync } from 'fs';
import * as fs from 'fs';
import { writeFileSync } from 'fs';

function delay(ms: number) {
return new Promise( resolve => setTimeout(resolve, ms) );
}

async function request(appID: string, appSecret: string, selfID: string) {
// const SelfSDK = require("self-sdk");
let opts = {'logLevel': 'debug'}
if (process.env["SELF_ENV"] != "") {
opts['env'] = process.env["SELF_ENV"]
}
let storageFolder = __dirname.split("/").slice(0,-1).join("/") + "/.self_storage"
const sdk = await SelfSDK.build( appID, appSecret, "random", storageFolder, opts);
await sdk.start()

let source = "supu"
let content = readFileSync("./my_image.png");
let obj = await sdk.newObject("test", content, "image/png")
// obj.save("./my_image_copy.jpg")

let fact = new FactToIssue("image", obj, source)
sdk.logger.info("fact created")

sdk.logger.info("issuing fact")
await sdk.facts().issue(selfID, [fact])

await delay(10000);
sdk.logger.info(`sending a fact request (${fact.key}) to ${selfID}`)
sdk.logger.info(`waiting for user input`)

try {
let res = await sdk.facts().request(selfID, [{
fact: fact.key,
issuers: [ appID ]
}])

if (!res) {
sdk.logger.warn(`fact request has timed out`)
} else if (res.status === 'accepted') {
let at = res.attestation(fact.key)
if (at != null) {
sdk.logger.info(`${selfID} digest is "${at.value}"`)
const o = await res.object(at.value)
o.save("./received.png")
sdk.logger.info(`result stored at /tmp/received.png`)
} else {
sdk.logger.warn(`No attestations have been returned`)
}
} else {
sdk.logger.warn(`${selfID} has rejected your authentication request`)
}
} catch (error) {
sdk.logger.error(error.toString())
}

sdk.close()
exit();
}

async function main() {
let appID = process.env["SELF_APP_ID"]
let appSecret = process.env["SELF_APP_SECRET"]
let selfID = process.env["SELF_USER_ID"]

await request(appID, appSecret, selfID);
}

main();



29 changes: 28 additions & 1 deletion src/chat-object.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Copyright 2020 Self Group Ltd. All Rights Reserved.
import { logging, Logger } from './logging'
import { createHash } from 'crypto';
import { writeFileSync } from 'fs';

/**
* FileObject represents an object (image or file) shared through messaging.
Expand All @@ -19,6 +21,7 @@ export class FileObject {
_sodium: any
logger: Logger
fi: RemoteFileInteractor
hash: string

/**
* Creates a new FileObject.
Expand All @@ -44,7 +47,7 @@ export class FileObject {
* @param mime mime type.
* @returns the current FileObject
*/
async buildFromData(name: string, data: string|Uint8Array, mime: string): Promise<FileObject> {
async buildFromData(name: string, data: Buffer, mime: string): Promise<FileObject> {
await this._sodium.ready;

// Encrypt the message
Expand All @@ -59,6 +62,8 @@ export class FileObject {
this.mime = mime
this.name = name
this.public = false
this.content = data
this.hash = this.calculateHash(data)

return this
}
Expand Down Expand Up @@ -87,6 +92,8 @@ export class FileObject {
}

this.content = buf

this.hash = this.calculateHash(this.content.toString('binary'))
this.link = input['link']
this.name = input['name']
this.mime = input['mime']
Expand All @@ -108,9 +115,15 @@ export class FileObject {
mime: this.mime,
expires: this.expires,
public: this.public,
object_hash: this.hash
}
}

save(path: string) {
// let newContent = Buffer.from(this.content, 'binary');
writeFileSync(path, this.content);
}

private encryptObject(plaintext: string|Uint8Array) {
const key = this._sodium.crypto_aead_xchacha20poly1305_ietf_keygen();
const pNonce = this._sodium.randombytes_buf(this._sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES);
Expand All @@ -125,6 +138,20 @@ export class FileObject {
return { key: this.buildShareableKey(key, pNonce), ciphertext: ct }
}

/**
* Calculates the sha256 hash for a given string.
* @param ct input to be hashed
* @returns the hash of the input.
*/
private calculateHash(ct: string|Uint8Array): string {
const hash = createHash('sha256');
hash.update(ct);
const base64Url = hash.digest().toString('base64').replace(/\+/g, '-').replace(/\//g, '_');
const urlSafeBase64Url = base64Url.replace(/=+$/, '');

return urlSafeBase64Url;
}

/**
* Extracts key and nonce from a shareable key
* @param key shareable key
Expand Down
2 changes: 1 addition & 1 deletion src/docs-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { FileObject } from './chat-object';

interface Doc {
name: string,
data: string|Uint8Array,
data: Buffer,
mime: string,
}
export default class DocsService {
Expand Down
2 changes: 1 addition & 1 deletion src/fact-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export default class FactResponse {

async object(hash: string): Promise<FileObject> {
for (const o of this.payload.objects) {
if (o.image_hash == hash) {
if (o.image_hash == hash || o.object_hash == hash) {
const fo = new FileObject(this.is.jwt.authToken(), this.is.url)
return fo.buildFromObject(o)
}
Expand Down
Loading

0 comments on commit 952d50a

Please sign in to comment.