crypto.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import { Injectable } from "@angular/core";
  2. import { TwitterApiProvider } from "../twitter-api/twitter-api";
  3. import { P2pStorageIpfsProvider } from "../p2p-storage-ipfs/p2p-storage-ipfs";
  4. import { Storage } from "@ionic/storage";
  5. import NodeRSA from "node-rsa";
  6. @Injectable()
  7. export class CryptoProvider {
  8. ownUserId: string;
  9. constructor(
  10. private twitter: TwitterApiProvider,
  11. private ipfs: P2pStorageIpfsProvider,
  12. private storage: Storage
  13. ) {
  14. this.init();
  15. }
  16. private async init() {
  17. this.ownUserId = await this.storage.get("userId");
  18. }
  19. public async publishPublicKey(key: string) {
  20. let publicKeyHistory = await this.getKeyHistory(this.ownUserId);
  21. // Todo: avoid publishing the same public key twice - check if new key equals newest key in history
  22. // Add new key to history
  23. const newKey = {
  24. key: key,
  25. validFrom: Date.now()
  26. };
  27. if (publicKeyHistory) {
  28. publicKeyHistory["keys"].push(newKey);
  29. } else {
  30. publicKeyHistory = {
  31. keys: [newKey]
  32. };
  33. }
  34. // Publish updated key history...
  35. const res = await this.ipfs.storePublicKey(publicKeyHistory);
  36. // ... and update description in user profile
  37. this.twitter.updateProfileDescription(
  38. "ipfs://" + res["Hash"] + " #hybridOSN"
  39. );
  40. }
  41. private async getKeyHistory(userId: string) {
  42. // Get user description
  43. const userData = await this.twitter.fetchUser(userId);
  44. const profileDescription = userData["description"];
  45. // Extract link to public key
  46. const link = this.extractLinkFromDescription(profileDescription);
  47. // Fetch public key history
  48. if (link.length) {
  49. return await this.ipfs.fetchJson(link);
  50. } else {
  51. return null;
  52. }
  53. }
  54. private extractLinkFromDescription(profileDescription: string): string {
  55. for (let word of profileDescription.split(" ")) {
  56. if (this.isLink(word)) {
  57. return word.substr(7);
  58. }
  59. }
  60. return "";
  61. }
  62. private isLink(word: string): boolean {
  63. const hits = word.match(/ipfs:\/\/Qm[a-zA-Z0-9]+/);
  64. return hits != null;
  65. }
  66. public async generateRsaKeys() {
  67. return await crypto.subtle.generateKey(
  68. {
  69. name: "RSA-OAEP",
  70. modulusLength: 1024,
  71. publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
  72. hash: { name: "SHA-256" }
  73. },
  74. true,
  75. ["encrypt", "decrypt"]
  76. );
  77. }
  78. public async extractPrivateKey(keys): Promise<string> {
  79. return btoa(
  80. String.fromCharCode.apply(
  81. null,
  82. new Uint8Array(await crypto.subtle.exportKey("pkcs8", keys.privateKey))
  83. )
  84. );
  85. }
  86. public async extractPublicKey(keys): Promise<string> {
  87. return btoa(
  88. String.fromCharCode.apply(
  89. null,
  90. new Uint8Array(await crypto.subtle.exportKey("spki", keys.publicKey))
  91. )
  92. );
  93. }
  94. public async isPublicKeyPublished(): Promise<boolean> {
  95. const publicKey = await this.storage.get("publicKey");
  96. const keyHistory = await this.getKeyHistory(this.ownUserId);
  97. if (keyHistory && publicKey.length) {
  98. const newestPublicKey = keyHistory["keys"].reverse()[0]["key"];
  99. return newestPublicKey === publicKey;
  100. } else {
  101. return false;
  102. }
  103. }
  104. public async isPrivateKeySet(): Promise<boolean> {
  105. const privateKey = await this.storage.get("privateKey");
  106. return privateKey.length > 0;
  107. }
  108. public encrypt(plainText: string, privateKey: string) {
  109. const key = new NodeRSA(
  110. `-----BEGIN PRIVATE KEY-----${privateKey}-----END PRIVATE KEY-----`
  111. );
  112. return key.encryptPrivate(plainText, "base64");
  113. }
  114. public decrypt(encryptedMessage: string, publicKey: string): string {
  115. const key = new NodeRSA(
  116. `-----BEGIN PUBLIC KEY-----${publicKey}-----END PUBLIC KEY-----`
  117. );
  118. return key.decryptPublic(encryptedMessage).toString();
  119. }
  120. }