index.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import crypto = require('libp2p-crypto');
  2. import util = require('util');
  3. import RsaPrivateKey = crypto.keys;
  4. import { Storage } from './storage';
  5. import { IWebClient } from './webclient';
  6. const TextEncoder = util.TextEncoder;
  7. import { encodeHex } from './util';
  8. import WebClientNode from './webclient-node';
  9. export class BankClient {
  10. private privateKey: RsaPrivateKey | undefined;
  11. private bootstrapPromise: any;
  12. private bootstrapResult: any;
  13. constructor(private urlBase: string, private storage: Storage = new Storage('bankClient'), private webClient: IWebClient = new WebClientNode()) {
  14. }
  15. public getPub(): Promise<string> {
  16. return new Promise(async (resolve, reject) => {
  17. await this.bootstrap();
  18. this.getPriv().id((idErr, pubHash) => {
  19. if (idErr) {
  20. return reject(idErr);
  21. }
  22. resolve(pubHash);
  23. });
  24. });
  25. }
  26. public bootstrap() {
  27. if (this.bootstrapResult) {
  28. return Promise.resolve(this.bootstrapResult);
  29. }
  30. if (this.bootstrapPromise) {
  31. return this.bootstrapPromise;
  32. }
  33. return this.bootstrapPromise = new Promise((resolve, reject) => {
  34. this.storage.get('notaprivatekey').then(privateKeyFromStorage => {
  35. if (privateKeyFromStorage == null) {
  36. console.log('no private key in storage. generating new');
  37. crypto.keys.generateKeyPair('RSA', 2048, (generateErr, privateKey) => {
  38. if (generateErr) {
  39. return reject(generateErr);
  40. }
  41. privateKey.export('password', (exportErr, exportResult) => {
  42. if (exportErr) {
  43. return reject(exportErr);
  44. }
  45. this.storage.set('notaprivatekey', exportResult).then(err => {
  46. // whatever
  47. }).catch(reject);
  48. this.privateKey = privateKey;
  49. resolve(true);
  50. });
  51. });
  52. } else {
  53. // console.log('importing privatekey');
  54. crypto.keys.import(privateKeyFromStorage, 'password', (err, importedPrivateKey) => {
  55. if (err) {
  56. return reject(err);
  57. }
  58. this.privateKey = importedPrivateKey;
  59. // console.log(this.getPublicKeyString());
  60. // console.log(privateKeyFromStorage);
  61. resolve(true);
  62. });
  63. }
  64. }).catch(reject);
  65. });
  66. }
  67. public async getNonce() {
  68. const nonce = await this.webClient.request({
  69. method: 'GET',
  70. url: this.urlBase + '/bank/nonce'
  71. });
  72. return Number(nonce);
  73. }
  74. public async getBalance(): Promise<number> {
  75. const nonce = await this.getNonce();
  76. const retrieveRequest = await this.makePlaintextPayload(JSON.stringify({
  77. _date: new Date().toISOString(),
  78. _nonce: nonce
  79. }));
  80. const topicURL = this.urlBase + '/bank/getbalance';
  81. const postResponse:any = await this.webClient.requestJSON({
  82. body: retrieveRequest,
  83. method: 'POST',
  84. url: topicURL
  85. });
  86. console.log('postResponse', postResponse);
  87. return postResponse.balance;
  88. }
  89. private getPriv(): RsaPrivateKey {
  90. if (!this.privateKey) {
  91. throw new Error('missing private key');
  92. }
  93. return this.privateKey;
  94. }
  95. private makePlaintextPayload(message: string) {
  96. const messageBytes = new TextEncoder().encode(message);
  97. return new Promise(async (resolve, reject) => {
  98. await this.bootstrap();
  99. this.privateKey.sign(messageBytes, async (signErr, signatureBytes) => {
  100. if (signErr) {
  101. reject(signErr);
  102. return;
  103. }
  104. const publicDERBytes = this.privateKey.public.bytes;
  105. this.privateKey.id((idErr, pubHash) => {
  106. if (idErr) {
  107. reject(idErr);
  108. return;
  109. }
  110. const result = {
  111. date: new Date().toISOString(),
  112. msg: encodeHex(messageBytes),
  113. pub: encodeHex(publicDERBytes),
  114. pubHash,
  115. sig: encodeHex(signatureBytes),
  116. };
  117. // console.log('result', result, signatureBytes);
  118. resolve(result);
  119. });
  120. });
  121. });
  122. }
  123. }