|
@@ -1,379 +0,0 @@
|
|
|
-import { Component } from "@angular/core";
|
|
|
-import {
|
|
|
- IonicPage,
|
|
|
- NavController,
|
|
|
- NavParams,
|
|
|
- LoadingController,
|
|
|
- AlertController
|
|
|
-} from "ionic-angular";
|
|
|
-import {
|
|
|
- FormBuilder,
|
|
|
- Validators,
|
|
|
- FormGroup,
|
|
|
- ValidatorFn,
|
|
|
- AbstractControl
|
|
|
-} from "@angular/forms";
|
|
|
-import { TwitterApiProvider } from "../../providers/twitter-api/twitter-api";
|
|
|
-import { Storage } from "@ionic/storage";
|
|
|
-import { P2pStorageIpfsProvider } from "../../providers/p2p-storage-ipfs/p2p-storage-ipfs";
|
|
|
-import { P2pDatabaseGunProvider } from "../../providers/p2p-database-gun/p2p-database-gun";
|
|
|
-import twittertext from "twitter-text";
|
|
|
-import { CryptoProvider } from "../../providers/crypto/crypto";
|
|
|
-import * as openpgp from 'openpgp';
|
|
|
-
|
|
|
-@IonicPage()
|
|
|
-@Component({
|
|
|
- selector: "page-write-tweet",
|
|
|
- templateUrl: "write-tweet.html"
|
|
|
-})
|
|
|
-export class WriteTweetPage {
|
|
|
- tweet: FormGroup;
|
|
|
- retweetId: string;
|
|
|
- replyToStatusId: string;
|
|
|
- retweet;
|
|
|
- replyTweet;
|
|
|
- openpgp;
|
|
|
- privateKey;
|
|
|
- publicKey;
|
|
|
- pk: any[]=[];
|
|
|
- passp = 'super long and hard to guess secret';
|
|
|
- hkp = new openpgp.HKP();
|
|
|
-
|
|
|
-
|
|
|
- constructor(
|
|
|
- public navCtrl: NavController,
|
|
|
- public navParams: NavParams,
|
|
|
- private formBuilder: FormBuilder,
|
|
|
- private twitter: TwitterApiProvider,
|
|
|
- private loadingCtrl: LoadingController,
|
|
|
- private storage: Storage,
|
|
|
- private ipfs: P2pStorageIpfsProvider,
|
|
|
- private gun: P2pDatabaseGunProvider,
|
|
|
- private cryptoUtils: CryptoProvider,
|
|
|
- private alertCtrl: AlertController
|
|
|
- ) {
|
|
|
- this.retweetId = this.navParams.get("tweetId");
|
|
|
- this.replyToStatusId = this.navParams.get("replyToStatus");
|
|
|
-
|
|
|
- this.tweet = this.formBuilder.group({
|
|
|
- text: [""],
|
|
|
- p2p: [false]
|
|
|
- });
|
|
|
-
|
|
|
- this.addValidators();
|
|
|
- // this.encryptDecryptFunction();
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-// public async encryptDecryptFunction () {
|
|
|
-// await openpgp.initWorker({path:'assets/scripts/openpgp.worker.js'});
|
|
|
-// let a = await this.generateKeys();
|
|
|
-// console.log('a is:',a.publicKeyArmored);
|
|
|
-// let b = await this.generateKeys();
|
|
|
-// console.log('b is:',b.publicKeyArmored);
|
|
|
-// let c = await this.generateKeys();
|
|
|
-// this.privateKey =c.privateKeyArmored;
|
|
|
-// this.publicKey = c.publicKeyArmored;
|
|
|
-
|
|
|
-// this.pk.push(a.publicKeyArmored);
|
|
|
-// this.pk.push(b.publicKeyArmored);
|
|
|
-// // this.pk = [`----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
|
-// // Version: OpenPGP.js v4.7.1
|
|
|
-// // Comment: https://openpgpjs.org
|
|
|
-
|
|
|
-// // xjMEXfAn1xYJKwYBBAHaRw8BAQdAAMVNOABw8MBtrtYR8KC3tSro3wITyApT
|
|
|
-// // TVjKVCppD+DNG0pvbiBTbWl0aCA8am9uQGV4YW1wbGUuY29tPsJ3BBAWCgAf
|
|
|
-// // BQJd8CfXBgsJBwgDAgQVCAoCAxYCAQIZAQIbAwIeAQAKCRD+efBRXzuMsfA7
|
|
|
-// // AQCEgoToFzv2hT9BREdiQp531/AHSyoZWmWvSZSvmga40gD8C+zwbCySnkhQ
|
|
|
-// // pb4L0DCKtSDa7pLg2g0OcxJlbSZWHQ3OOARd8CfXEgorBgEEAZdVAQUBAQdA
|
|
|
-// // p4mVY17dPWf6VCBqW10Ybk5JgUO6FK0OsETWw3gG2zcDAQgHwmEEGBYIAAkF
|
|
|
-// // Al3wJ9cCGwwACgkQ/nnwUV87jLFHbAD9GyoL7dcTDGQoqtrhKozdgnzfugTb
|
|
|
-// // er0bwU15WNMjefkA/jEqK9YUNcRrFKIuac9PVibGgutL8ak7ukysw6iTcCsM
|
|
|
-// // =fmhE
|
|
|
-// // -----END PGP PUBLIC KEY BLOCK-----`,
|
|
|
-// // `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
|
-// // Version: OpenPGP.js v4.7.1
|
|
|
-// // Comment: https://openpgpjs.org
|
|
|
-
|
|
|
-// // xjMEXfAn1hYJKwYBBAHaRw8BAQdAsF1ivpd0HU8ogj02LDv6BTOxNMWGZaEc
|
|
|
-// // OyZBwqoYJPrNG0pvbiBTbWl0aCA8am9uQGV4YW1wbGUuY29tPsJ3BBAWCgAf
|
|
|
-// // BQJd8CfWBgsJBwgDAgQVCAoCAxYCAQIZAQIbAwIeAQAKCRDEruv77flRJ32B
|
|
|
-// // AP93GIBcUW2okROoZZhdPVeqjRD72Ft64imXpdZ0jx4ohgEA5Kv9vs2kV73q
|
|
|
-// // k6fcdf7qD/i5gMExU0+vV05c9VxBYwfOOARd8CfWEgorBgEEAZdVAQUBAQdA
|
|
|
-// // 1J7E03ZopUnsIeNzeiZvba6qxhhUbpmBZ1aN1HhWUlEDAQgHwmEEGBYIAAkF
|
|
|
-// // Al3wJ9YCGwwACgkQxK7r++35USdTqQD/ZEg8X5tMx75nQe4mGlyiRjmmtWLw
|
|
|
-// // n9bslTdjBIszs/EA/R1WIm6ji4Ru1dJWc3ISisz78xTM2H8U7fnP8yjFcWcD
|
|
|
-// // =hgnW
|
|
|
-// // -----END PGP PUBLIC KEY BLOCK-----`];
|
|
|
-// console.log('array of pub keys is :',this.pk);
|
|
|
-// this.pk = this.pk.map(async (key) => {
|
|
|
-// return (await openpgp.key.readArmored(key)).keys[0]
|
|
|
-// });
|
|
|
-
|
|
|
-// console.log('priv key: ',this.privateKey,'this.pubkey',this.pk);
|
|
|
-// let encrypted;
|
|
|
-// const privKeyObj = (await openpgp.key.readArmored(this.privateKey)).keys[0];
|
|
|
-// console.log('privKeyObj',privKeyObj);
|
|
|
-// const bla = await privKeyObj.decrypt(this.passp);
|
|
|
-
|
|
|
-// // const options = {
|
|
|
-// // message: openpgp.message.fromText('Hello, World!'), // input as Message object
|
|
|
-// // publicKeys: (await openpgp.key.readArmored(this.publicKey)).keys, // for encryption
|
|
|
-// // privateKeys: [privKeyObj] // for signing (optional)
|
|
|
-// // }
|
|
|
-
|
|
|
-// const options = {
|
|
|
-// message: openpgp.message.fromText('Hello, World!'), // input as Message object
|
|
|
-// publicKeys: await Promise.all(this.pk), // for encryption
|
|
|
-// privateKeys: [privKeyObj] // for signing (optional)
|
|
|
-// }
|
|
|
-
|
|
|
-// const ciphertext = await openpgp.encrypt(options);
|
|
|
-// encrypted = ciphertext.data; // '-----BEGIN PGP MESSAGE ... END PGP MESSAGE-----'
|
|
|
-// console.log('encrypted is:',encrypted);
|
|
|
-
|
|
|
-// let aprivKeyObj = (await openpgp.key.readArmored(a.privateKeyArmored)).keys[0];
|
|
|
-// await aprivKeyObj.decrypt(this.passp);
|
|
|
-
|
|
|
-// const options2 = {
|
|
|
-// message: await openpgp.message.readArmored(encrypted), // parse armored message
|
|
|
-// privateKeys: [aprivKeyObj] // for decryption
|
|
|
-// }
|
|
|
-// console.log('options2 is: ',options2);
|
|
|
-// let plaintext = await openpgp.decrypt(options2);
|
|
|
-// console.log('decrypted text is:',plaintext,plaintext.data);
|
|
|
-// return plaintext.data // 'Hello, World!'
|
|
|
-
|
|
|
-// }
|
|
|
-
|
|
|
- // public async generateKeys(){
|
|
|
- // let options = {
|
|
|
- // userIds: [{ name:'Jon Smith', email:'jon@example.com' }], // multiple user IDs
|
|
|
- // curve: "ed25519", // ECC curve name
|
|
|
- // passphrase: this.passp // protects the private key
|
|
|
- // };
|
|
|
-
|
|
|
- // let a = await openpgp.generateKey(options);
|
|
|
- // return a;
|
|
|
- // // console.log('resolved a = ',a);
|
|
|
- // // this.privateKey =a.privateKeyArmored;
|
|
|
- // // this.publicKey = a.publicKeyArmored;
|
|
|
- // // this.encryptDecryptFunction();
|
|
|
- // }
|
|
|
-
|
|
|
-
|
|
|
- private async addValidators() {
|
|
|
- const triggerWords = await this.storage.get("keywords");
|
|
|
- const validators = [
|
|
|
- Validators.maxLength(140),
|
|
|
- this.containsTriggerWord(triggerWords)
|
|
|
- ];
|
|
|
- this.tweet.controls["text"].setValidators(validators);
|
|
|
- }
|
|
|
-
|
|
|
- private containsTriggerWord(triggerWords: string): ValidatorFn {
|
|
|
- return (control: AbstractControl): { [key: string]: any } | null => {
|
|
|
- if (triggerWords) {
|
|
|
- const regexList = triggerWords
|
|
|
- .toLowerCase()
|
|
|
- .split(", ")
|
|
|
- .join("|");
|
|
|
- const regex = new RegExp(regexList);
|
|
|
- const containsTriggerWord = regex.test(control.value.toLowerCase());
|
|
|
- return containsTriggerWord
|
|
|
- ? { containsTriggerWord: { value: control.value } }
|
|
|
- : null;
|
|
|
- } else {
|
|
|
- return null;
|
|
|
- }
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- async ionViewDidLoad() {
|
|
|
- if (this.retweetId) {
|
|
|
- this.retweet = await this.twitter.fetchTweet(this.retweetId);
|
|
|
- }
|
|
|
- if (this.replyToStatusId) {
|
|
|
- this.replyTweet = await this.twitter.fetchTweet(this.replyToStatusId);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- get tweetCharProgress() {
|
|
|
- const progress = 1 - this.tweet.value["text"].length / 140;
|
|
|
- const radius = 8;
|
|
|
- const circumference = Math.PI * radius * 2;
|
|
|
- return progress * circumference;
|
|
|
- }
|
|
|
-
|
|
|
- get showTrigger(): boolean {
|
|
|
- return (
|
|
|
- this.tweet &&
|
|
|
- this.tweet.controls &&
|
|
|
- this.tweet.controls.text &&
|
|
|
- this.tweet.controls.text.errors &&
|
|
|
- this.tweet.controls.text.errors["containsTriggerWord"] &&
|
|
|
- !this.tweet.controls.p2p.value
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- showTriggerInfo() {
|
|
|
- this.alertCtrl
|
|
|
- .create({
|
|
|
- title: "Watch Out!",
|
|
|
- message:
|
|
|
- "Your tweet contains words you have previously defined to only share securely via P2P. Currently P2P mode is not selected.",
|
|
|
- buttons: ["OK"]
|
|
|
- })
|
|
|
- .present();
|
|
|
- }
|
|
|
-
|
|
|
- async submitTweet() {
|
|
|
- console.log('Submitting tweet')
|
|
|
- const loading = this.loadingCtrl.create();
|
|
|
- loading.present();
|
|
|
-
|
|
|
- if (this.tweet.value.p2p) {
|
|
|
- loading.setContent("Validate keys...");
|
|
|
- if (
|
|
|
- (await this.cryptoUtils.isPrivateKeySet()) &&
|
|
|
- (await this.cryptoUtils.isPublicKeyPublished())
|
|
|
- ) {
|
|
|
- loading.setContent("Publish private tweet...");
|
|
|
- await this.tweetPrivate();
|
|
|
- } else {
|
|
|
- loading.dismiss();
|
|
|
- const alert = this.alertCtrl.create({
|
|
|
- title: "Oooops...",
|
|
|
- message:
|
|
|
- "Please verify that you have set a private and public key in the settings and that your latest public key was published."
|
|
|
- });
|
|
|
- alert.present();
|
|
|
- return;
|
|
|
- }
|
|
|
- } else {
|
|
|
- loading.setContent("Publish on Twitter...");
|
|
|
- await this.twitter.tweet(
|
|
|
- this.tweet.value["text"],
|
|
|
- this.retweet,
|
|
|
- this.replyToStatusId
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- loading.dismiss();
|
|
|
- this.navCtrl.pop();
|
|
|
- }
|
|
|
-
|
|
|
- public async lookupKeys(email:string){
|
|
|
- var options = {
|
|
|
- query: email
|
|
|
- };
|
|
|
-
|
|
|
- let armoredPubkey = await this.hkp.lookup(options);
|
|
|
- console.log('armord pubkey',armoredPubkey);
|
|
|
-
|
|
|
- let pubkey = (await openpgp.key.readArmored(armoredPubkey));
|
|
|
- // console.log('array of opubkes returened from server',pubkey);
|
|
|
-
|
|
|
- pubkey = (await openpgp.key.readArmored(armoredPubkey)).keys[0];
|
|
|
- // console.log('latest pubkey is:',pubkey);
|
|
|
- // console.log('Found public key:',pubkey);
|
|
|
-
|
|
|
- this.pk.push(pubkey);
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- private async tweetPrivate() {
|
|
|
- const tweet = await this.buildPrivateTweet();
|
|
|
- console.log('tweet is:',tweet.full_text);
|
|
|
- const privateKey = await this.storage.get("privateKey");
|
|
|
- //fetch followers and their public keys
|
|
|
- //assuming the email id of rohit.shiva.gowda
|
|
|
- await this.lookupKeys('rohit.hosn@gmail.com');
|
|
|
-
|
|
|
-
|
|
|
- console.log('array of pub keys is :', this.pk);
|
|
|
- this.pk = this.pk.map(async (key) => {
|
|
|
- console.log('key is:',key);
|
|
|
- return (await openpgp.key.readArmored(key)).keys[0]
|
|
|
- });
|
|
|
-
|
|
|
- console.log("after mapping", this.pk);
|
|
|
-
|
|
|
- const options = {
|
|
|
- message: openpgp.message.fromText(tweet), // input as Message object
|
|
|
- publicKeys: await Promise.all(this.pk), // for encryption
|
|
|
- // privateKeys: [privKeyObj] // for signing (optional)
|
|
|
- }
|
|
|
-
|
|
|
- const ciphertext = await openpgp.encrypt(options);
|
|
|
-
|
|
|
- const encryptedTweet = ciphertext.data;
|
|
|
- console.log('encrypted tweet is:',encryptedTweet);
|
|
|
-
|
|
|
- // const encryptedTweet = this.cryptoUtils.encrypt(
|
|
|
- // JSON.stringify(tweet),
|
|
|
- // privateKey
|
|
|
- // );
|
|
|
- const res = await this.ipfs.storeTweet(encryptedTweet);
|
|
|
-
|
|
|
- this.gun.storeLastTweetHashForUser(
|
|
|
- tweet.user_id,
|
|
|
- res["Hash"],
|
|
|
- tweet.created_at
|
|
|
- );
|
|
|
-
|
|
|
- this.gun.publishHashtags(tweet.entities.hashtags);
|
|
|
- }
|
|
|
-
|
|
|
- private async buildPrivateTweet() {
|
|
|
- const status = this.tweet.value["text"].trim();
|
|
|
- const entities = await this.getEntities(status);
|
|
|
-
|
|
|
- return {
|
|
|
- full_text: status,
|
|
|
- user_id: await this.storage.get("userId"),
|
|
|
- created_at: Date.now(),
|
|
|
- private_tweet: true,
|
|
|
- in_reply_to_status_id: this.replyToStatusId,
|
|
|
- quoted_status_id: this.retweetId,
|
|
|
- display_text_range: [0, status.length],
|
|
|
- entities: entities
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- private async getEntities(status: string) {
|
|
|
- return {
|
|
|
- hashtags: twittertext.extractHashtagsWithIndices(status),
|
|
|
- urls: twittertext.extractUrlsWithIndices(status),
|
|
|
- user_mentions: await this.getMentions(status)
|
|
|
- };
|
|
|
- }
|
|
|
-
|
|
|
- private async getMentions(status: string) {
|
|
|
- // extract mentions
|
|
|
- const entities = twittertext.extractMentionsWithIndices(status);
|
|
|
-
|
|
|
- // add user_id
|
|
|
- const entitiesWithPromises = entities.map(async mention => {
|
|
|
- try {
|
|
|
- const user = await this.twitter.fetchUserFromScreenName(
|
|
|
- mention.screenName
|
|
|
- );
|
|
|
- mention["id_str"] = user[0]["id_str"];
|
|
|
- mention["screen_name"] = mention.screenName;
|
|
|
- delete mention.screenName;
|
|
|
- } catch (err) {
|
|
|
- console.error(
|
|
|
- "There is no user signed up to twitter with username: " +
|
|
|
- mention.screenName
|
|
|
- );
|
|
|
- }
|
|
|
- return mention;
|
|
|
- });
|
|
|
-
|
|
|
- // filter for valid users and return
|
|
|
- return (await Promise.all(entitiesWithPromises)).filter(el =>
|
|
|
- el.hasOwnProperty("id_str")
|
|
|
- );
|
|
|
- }
|
|
|
-}
|