user 6 سال پیش
والد
کامیت
8eab305f4c
13فایلهای تغییر یافته به همراه5745 افزوده شده و 153 حذف شده
  1. 1 0
      .gitignore
  2. 28 0
      .vscode/launch.json
  3. 37 0
      __tests__/index.test.ts
  4. 7 0
      jestconfig.json
  5. 5 1
      lib/index.d.ts
  6. 51 1
      lib/index.js
  7. 5459 147
      package-lock.json
  8. 10 1
      package.json
  9. 76 1
      src/index.ts
  10. 54 0
      src/storage.ts
  11. 7 0
      src/webclient-options.ts
  12. 6 0
      src/webclient.ts
  13. 4 2
      tsconfig.json

+ 1 - 0
.gitignore

@@ -1 +1,2 @@
 /node_modules
+data

+ 28 - 0
.vscode/launch.json

@@ -0,0 +1,28 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "Current TS File",
+            "type": "node",
+            "request": "launch",
+            "args": ["${relativeFile}"],
+            "runtimeArgs": ["--nolazy", "-r", "ts-node/register"],
+            "sourceMaps": true,
+            "cwd": "${workspaceRoot}",
+            "protocol": "inspector",
+        },
+        {
+            "type": "node",
+            "request": "launch",
+            "name": "Launch Program",
+            "program": "${workspaceFolder}/lib/index.js",
+            "preLaunchTask": "tsc: build - tsconfig.json",
+            "outFiles": [
+                "${workspaceFolder}/lib/**/*.js"
+            ]
+        }
+    ]
+}

+ 37 - 0
__tests__/index.test.ts

@@ -0,0 +1,37 @@
+import { BankClient } from '../src/index';
+import { IWebClient } from '../src/webclient';
+import { Storage } from './../src/storage';
+import { IWebClientOptions } from './../src/webclient-options';
+
+describe('BankClient', () => {
+    const storage = new Storage('bankConfig');
+
+    test('should successfully bootstrap', async () => {
+      class FakeWebClient implements IWebClient {
+        public requestJSON(options: object): Promise<object> {
+          throw new Error("Method not implemented.");
+        }
+        public request(options: IWebClientOptions): Promise<string> {
+          throw new Error("Method not implemented.");
+        }
+      }
+      const bankClient = new BankClient('/urlBase', storage, new FakeWebClient());
+      const strapped = await bankClient.bootstrap();
+      expect(strapped).toBeDefined();
+  });
+
+    test('should return hardcoded nonce', async () => {
+      class FakeWebClient implements IWebClient {
+        public requestJSON(options: object): Promise<object> {
+          throw new Error("Method not implemented.");
+        }
+        public request(options: IWebClientOptions): Promise<string> {
+          return Promise.resolve('42');
+        }
+      }
+      const bankClient = new BankClient('/urlBase', storage, new FakeWebClient());
+      await bankClient.bootstrap();
+      const nonce = await bankClient.getNonce();
+      expect(nonce).toEqual(42);
+  });
+});

+ 7 - 0
jestconfig.json

@@ -0,0 +1,7 @@
+{
+  "transform": {
+    "^.+\\.(t|j)sx?$": "ts-jest"
+  },
+  "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
+  "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node"]
+}

+ 5 - 1
lib/index.d.ts

@@ -1 +1,5 @@
-export declare const Greeter: (name: string) => string;
+export declare class BankClient {
+    private urlBase;
+    constructor(urlBase: string);
+    upload(): Promise<void>;
+}

+ 51 - 1
lib/index.js

@@ -1,3 +1,53 @@
 "use strict";
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+    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) : new P(function (resolve) { resolve(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 };
+    }
+};
 Object.defineProperty(exports, "__esModule", { value: true });
-exports.Greeter = function (name) { return "Hello " + name; };
+var BankClient = /** @class */ (function () {
+    function BankClient(urlBase) {
+        this.urlBase = urlBase;
+    }
+    BankClient.prototype.upload = function () {
+        return __awaiter(this, void 0, void 0, function () {
+            return __generator(this, function (_a) {
+                // tslint:disable-next-line: no-console
+                console.log('hey');
+                return [2 /*return*/];
+            });
+        });
+    };
+    return BankClient;
+}());
+exports.BankClient = BankClient;

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 5459 - 147
package-lock.json


+ 10 - 1
package.json

@@ -3,8 +3,9 @@
   "version": "1.0.0",
   "description": "",
   "main": "lib/index.js",
+  "types": "lib/index.d.ts",
   "scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1",
+    "test": "jest --config jestconfig.json",
     "build": "tsc",
     "format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"",
     "lint": "tslint -p tsconfig.json"
@@ -13,9 +14,17 @@
   "author": "",
   "license": "ISC",
   "devDependencies": {
+    "@types/jest": "^24.0.15",
+    "@types/node": "^12.6.2",
+    "jest": "^24.8.0",
     "prettier": "^1.18.2",
+    "ts-jest": "^24.0.2",
+    "ts-node": "^8.3.0",
     "tslint": "^5.18.0",
     "tslint-config-prettier": "^1.18.0",
     "typescript": "^3.5.3"
+  },
+  "dependencies": {
+    "libp2p-crypto": "^0.16.1"
   }
 }

+ 76 - 1
src/index.ts

@@ -1 +1,76 @@
-export const Greeter = (name: string) => `Hello ${name}`;
+import crypto = require('libp2p-crypto');
+import { Storage } from './storage';
+import { IWebClient } from './webclient';
+
+export class BankClient {
+
+    private privateKey: any;
+    private bootstrapPromise: any;
+    private bootstrapResult: any;
+
+    constructor(private urlBase: string, private storage: Storage, private webClient: IWebClient) {
+
+    }
+
+    public getPub(): Promise<string> {
+      return new Promise(async (resolve, reject) => {
+        await this.bootstrap();
+        this.privateKey.id((idErr, pubHash) => {
+          if (idErr) {
+            return reject(idErr);
+          }
+          resolve(pubHash);
+        });
+      });
+    }
+  
+    public bootstrap() {
+      if (this.bootstrapResult) {
+        return Promise.resolve(this.bootstrapResult);
+      }
+      if (this.bootstrapPromise) {
+        return this.bootstrapPromise;
+      }
+      return this.bootstrapPromise = new Promise((resolve, reject) => {
+        this.storage.get('notaprivatekey').then(privateKeyFromStorage => {
+          if (privateKeyFromStorage == null) {
+            console.log('no private key in storage. generating new');
+            crypto.keys.generateKeyPair('RSA', 2048, (generateErr, privateKey) => {
+              if (generateErr) {
+                return reject(generateErr);
+              }
+              privateKey.export('password', (exportErr, exportResult) => {
+                if (exportErr) {
+                  return reject(exportErr);
+                }
+                this.storage.set('notaprivatekey', exportResult).then(err => {
+                    // whatever
+                }).catch(reject);
+                this.privateKey = privateKey;
+                resolve(true);
+              });
+            });
+          } else {
+            // console.log('importing privatekey');
+            crypto.keys.import(privateKeyFromStorage, 'password', (err, importedPrivateKey) => {
+              if (err) {
+                return reject(err);
+              }
+              this.privateKey = importedPrivateKey;
+              // console.log(this.getPublicKeyString());
+              // console.log(privateKeyFromStorage);
+              resolve(true);
+            });
+          }
+        }).catch(reject);
+      });
+    }
+  
+    public async getNonce() {
+      const nonce = await this.webClient.request({
+        method: 'GET',
+        url: this.urlBase + '/bank/nonce'
+      });
+      return Number(nonce);
+    }
+}

+ 54 - 0
src/storage.ts

@@ -0,0 +1,54 @@
+import fs = require('fs');
+
+export class Storage {
+
+    private prefix: string;
+
+    constructor(id:string) {
+        try {
+            fs.mkdirSync("data");
+        } catch (e) {
+            // ignore
+        }
+        const safeId = id.replace(/[^A-Za-z0-9]/g, "");
+        if (safeId === '') {
+            throw new Error("must have non-empty id");
+        }
+        this.prefix = safeId;
+    }
+
+    public async getValues() {
+        return Object.values(this.getMap());
+    }
+
+    public async get(key:string) {
+        return this.getMap()[key];
+    }
+
+    public async put(key:string, value:any) {
+        const filename = "data/storage_" + this.prefix;
+        let map;
+        try {
+            const contents = fs.readFileSync(filename, {encoding: 'utf-8'});
+            map = JSON.parse(contents);
+        } catch(e) {
+            map = {};
+        }
+        map[key] = value;
+        fs.writeFileSync(filename, JSON.stringify(map));
+    }
+
+    public async set(key:string, value:any) {
+        return await this.put(key, value);
+    }
+
+    private getMap() {
+        try {
+            const filename = "data/storage_" + this.prefix;
+            const contents = fs.readFileSync(filename, {encoding: 'utf-8'});
+            return JSON.parse(contents);
+        } catch (e) {
+            return {};
+        }
+    }
+}

+ 7 - 0
src/webclient-options.ts

@@ -0,0 +1,7 @@
+import { request } from "https";
+
+export interface IWebClientOptions {
+    method: string;
+    url: string;
+    headers?: object;
+}

+ 6 - 0
src/webclient.ts

@@ -0,0 +1,6 @@
+import { request } from "https";
+
+export interface IWebClient {
+    request(options: object): Promise<string>;
+    requestJSON(options: object): Promise<object>;
+}

+ 4 - 2
tsconfig.json

@@ -1,10 +1,12 @@
 {
     "compilerOptions": {
-      "target": "es5",
+      "target": "es2016",
       "module": "commonjs",
       "declaration": true,
       "outDir": "./lib",
-      "strict": true
+      "strict": true,
+      "noImplicitAny": false,
+      "sourceMap": true
     },
     "include": ["src"],
     "exclude": ["node_modules", "**/__tests__/*"]