diff --git a/.eslintignore b/.eslintignore
index ff968ce0e..6ef379a1c 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -12,6 +12,7 @@ test/views/*.js
# Generated files
js/components.js
js/libtextsecure.js
+js/libloki.js
js/util_worker.js
js/libsignal-protocol-worker.js
libtextsecure/components.js
diff --git a/.gitignore b/.gitignore
index b1b7020d1..586046d86 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,7 @@ sql/
js/components.js
js/util_worker.js
js/libtextsecure.js
+js/libloki.js
libtextsecure/components.js
libtextsecure/test/test.js
stylesheets/*.css
diff --git a/.prettierignore b/.prettierignore
index 756580e19..e6db8458c 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -8,6 +8,7 @@ dist/**
js/components.js
js/util_worker.js
js/libtextsecure.js
+js/libloki.js
libtextsecure/components.js
libtextsecure/test/test.js
stylesheets/*.css
diff --git a/Gruntfile.js b/Gruntfile.js
index 77815ff86..b05512dac 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -86,6 +86,12 @@ module.exports = grunt => {
],
dest: 'js/libtextsecure.js',
},
+ libloki: {
+ src: [
+ 'libloki/libloki-protocol.js',
+ ],
+ dest: 'js/libloki.js',
+ },
libtextsecuretest: {
src: [
'node_modules/jquery/dist/jquery.js',
@@ -128,6 +134,10 @@ module.exports = grunt => {
files: ['./libtextsecure/*.js', './libtextsecure/storage/*.js'],
tasks: ['concat:libtextsecure'],
},
+ libloki: {
+ files: ['./libloki/*.js'],
+ tasks: ['concat:libloki'],
+ },
protobuf: {
files: ['./protos/SignalService.proto'],
tasks: ['exec:build-protobuf'],
diff --git a/background.html b/background.html
index ac4c1869c..8af81e984 100644
--- a/background.html
+++ b/background.html
@@ -584,6 +584,7 @@
+
diff --git a/libloki/libloki-protocol.js b/libloki/libloki-protocol.js
new file mode 100644
index 000000000..5cf9e5cfe
--- /dev/null
+++ b/libloki/libloki-protocol.js
@@ -0,0 +1,47 @@
+/* global window, libsignal, textsecure */
+
+// eslint-disable-next-line func-names
+(function() {
+ window.libloki = window.libloki || {};
+
+ const IV_LENGTH = 16;
+
+ FallBackSessionCipher = function (address) {
+ this.pubKey = StringView.hexToArrayBuffer(address.getName());
+
+ this.encrypt = async (plaintext) => {
+ const myKeyPair = await textsecure.storage.protocol.getIdentityKeyPair();
+ const myPrivateKey = myKeyPair.privKey;
+ const symmetricKey = libsignal.Curve.calculateAgreement(this.pubKey, myPrivateKey);
+ const iv = libsignal.crypto.getRandomBytes(IV_LENGTH);
+ const ciphertext = await libsignal.crypto.encrypt(symmetricKey, plaintext, iv);
+ const ivAndCiphertext = new Uint8Array(
+ iv.byteLength + ciphertext.byteLength
+ );
+ ivAndCiphertext.set(new Uint8Array(iv));
+ ivAndCiphertext.set(
+ new Uint8Array(ciphertext),
+ iv.byteLength
+ );
+
+ return {
+ type : 6, //friend request
+ body : new dcodeIO.ByteBuffer.wrap(ivAndCiphertext).toString('binary'),
+ registrationId : null
+ };
+ },
+
+ this.decrypt = async (ivAndCiphertext) => {
+ const iv = ivAndCiphertext.slice(0, IV_LENGTH);
+ const cipherText = ivAndCiphertext.slice(IV_LENGTH);
+ const myKeyPair = await textsecure.storage.protocol.getIdentityKeyPair();
+ const myPrivateKey = myKeyPair.privKey;
+ const symmetricKey = libsignal.Curve.calculateAgreement(this.pubKey, myPrivateKey);
+ const plaintext = await libsignal.crypto.decrypt(symmetricKey, cipherText, iv);
+ return plaintext;
+ }
+ }
+
+ window.libloki.FallBackSessionCipher = FallBackSessionCipher;
+
+})();
\ No newline at end of file
diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js
index 7217c0f36..6381a173c 100644
--- a/libtextsecure/message_receiver.js
+++ b/libtextsecure/message_receiver.js
@@ -646,10 +646,17 @@ MessageReceiver.prototype.extend({
case textsecure.protobuf.Envelope.Type.CIPHERTEXT:
window.log.info('message from', this.getEnvelopeId(envelope));
promise = Promise.resolve(ciphertext.toArrayBuffer())//;sessionCipher
- // TODO: restore decryption & unpadding
+ // TODO: restore decryption & unpadding (?)
//.decryptWhisperMessage(ciphertext)
//.then(this.unpad);
break;
+ case textsecure.protobuf.Envelope.Type.FRIEND_REQUEST:
+ window.log.info('friend-request message from ', envelope.source)
+ const fallBackSessionCipher = new libloki.FallBackSessionCipher(
+ address
+ );
+ promise = fallBackSessionCipher.decrypt(ciphertext.toArrayBuffer());
+ break;
case textsecure.protobuf.Envelope.Type.PREKEY_BUNDLE:
window.log.info('prekey message from', this.getEnvelopeId(envelope));
promise = this.decryptPreKeyWhisperMessage(
diff --git a/libtextsecure/outgoing_message.js b/libtextsecure/outgoing_message.js
index 25915c630..140ba404a 100644
--- a/libtextsecure/outgoing_message.js
+++ b/libtextsecure/outgoing_message.js
@@ -1,4 +1,4 @@
-/* global textsecure, libsignal, window, btoa */
+/* global textsecure, libsignal, window, btoa, libloki */
/* eslint-disable more/no-then */
@@ -209,7 +209,7 @@ OutgoingMessage.prototype = {
content: outgoingObject.content,
});
const requestMessage = new textsecure.protobuf.WebSocketRequestMessage({
- id: new Uint8Array(libsignal.crypto.getRandomBytes(1))[0],
+ id: new Uint8Array(libsignal.crypto.getRandomBytes(1))[0], // random ID for now
verb: 'PUT',
path: '/api/v1/message',
body: messageEnvelope.encode().toArrayBuffer()
@@ -239,32 +239,7 @@ OutgoingMessage.prototype = {
let sessionCipher;
if (this.fallBackEncryption) {
- // TODO: move to own file?
- FallBackSessionCipher = function (address) {
- this.recipientPubKey = StringView.hexToArrayBuffer(address.getName());
- this.encrypt = async (plaintext) => {
- const myKeyPair = await textsecure.storage.protocol.getIdentityKeyPair();
- const myPrivateKey = myKeyPair.privKey;
- const symmetricKey = libsignal.Curve.calculateAgreement(this.recipientPubKey, myPrivateKey);
- const iv = libsignal.crypto.getRandomBytes(16);
- const ciphertext = await libsignal.crypto.encrypt(symmetricKey, plaintext, iv);
- const ivAndCiphertext = new Uint8Array(
- iv.byteLength + ciphertext.byteLength
- );
- ivAndCiphertext.set(new Uint8Array(iv));
- ivAndCiphertext.set(
- new Uint8Array(ciphertext),
- iv.byteLength
- );
-
- return {
- type : 6, //friend request
- body : new dcodeIO.ByteBuffer.wrap(ivAndCiphertext).toString('binary'),
- registrationId : null
- };
- }
- }
- sessionCipher = new FallBackSessionCipher(
+ sessionCipher = new libloki.FallBackSessionCipher(
address
);
} else {
diff --git a/ts/util/lint/linter.ts b/ts/util/lint/linter.ts
index c274aadb9..29bc5f939 100644
--- a/ts/util/lint/linter.ts
+++ b/ts/util/lint/linter.ts
@@ -52,6 +52,7 @@ const excludedFiles = [
// Generated files
'^js/components.js',
'^js/libtextsecure.js',
+ '^js/libloki.js',
'^js/util_worker.js',
'^libtextsecure/components.js',
'^libtextsecure/test/test.js',