8 changed files with 289 additions and 77 deletions
-
1app/views/chat.tpl
-
3app/widgets/Chat/Chat.php
-
21app/widgets/Chat/chat_omemo.js
-
34app/widgets/ChatOmemo/ChatOmemo.php
-
73app/widgets/ChatOmemo/chatomemo.js
-
122app/widgets/ChatOmemo/chatomemo_storage.js
-
0app/widgets/ChatOmemo/libsignal_protocol.js
-
112public/scripts/movim_utils.js
@ -1,21 +0,0 @@ |
|||
var KeyHelper = libsignal.KeyHelper; |
|||
|
|||
var registrationId = KeyHelper.generateRegistrationId(); |
|||
// Store registrationId somewhere durable and safe.
|
|||
console.log(registrationId); |
|||
|
|||
KeyHelper.generateIdentityKeyPair().then(function(identityKeyPair) { |
|||
console.log(identityKeyPair); |
|||
// keyPair -> { pubKey: ArrayBuffer, privKey: ArrayBuffer }
|
|||
// Store identityKeyPair somewhere durable and safe.
|
|||
}); |
|||
|
|||
KeyHelper.generatePreKey(1).then(function(preKey) { |
|||
console.log('preKey'); |
|||
console.log(preKey); |
|||
store.storePreKey(preKey.keyId, preKey.keyPair); |
|||
}); |
|||
|
|||
KeyHelper.generateSignedPreKey(identityKeyPair, keyId).then(function(signedPreKey) { |
|||
store.storeSignedPreKey(signedPreKey.keyId, signedPreKey.keyPair); |
|||
}); |
@ -0,0 +1,34 @@ |
|||
<?php |
|||
|
|||
use Moxl\Xec\Action\OMEMO\AnnounceBundle; |
|||
use Moxl\Xec\Action\OMEMO\SetDeviceList; |
|||
|
|||
class ChatOmemo extends \Movim\Widget\Base |
|||
{ |
|||
public function load() |
|||
{ |
|||
$this->addjs('libsignal_protocol.js'); |
|||
$this->addjs('chatomemo.js'); |
|||
$this->addjs('chatomemo_storage.js'); |
|||
} |
|||
|
|||
public function ajaxAnnounceBundle($bundle) |
|||
{ |
|||
$preKeys = []; |
|||
foreach ($bundle->preKeys as $preKey) { |
|||
array_push($preKeys, (string)$preKey->key); |
|||
} |
|||
|
|||
$sdl = new SetDeviceList; |
|||
$sdl->setList([$bundle->deviceId]) |
|||
->request(); |
|||
|
|||
$ab = new AnnounceBundle; |
|||
$ab->setId($bundle->deviceId) |
|||
->setSignedPreKeyPublic($bundle->signedPreKey->publicKey) |
|||
->setSignedPreKeySignature($bundle->signedPreKey->signature) |
|||
->setIdentityKey($bundle->identityKey) |
|||
->setPreKeys($preKeys) |
|||
->request(); |
|||
} |
|||
} |
@ -0,0 +1,73 @@ |
|||
var KeyHelper = libsignal.KeyHelper; |
|||
/* |
|||
var deviceId = KeyHelper.generateRegistrationId(); |
|||
// Store deviceId somewhere durable and safe.
|
|||
console.log(deviceId); |
|||
|
|||
KeyHelper.generateIdentityKeyPair().then(function(identityKeyPair) { |
|||
console.log(identityKeyPair); |
|||
// keyPair -> { pubKey: ArrayBuffer, privKey: ArrayBuffer }
|
|||
// Store identityKeyPair somewhere durable and safe.
|
|||
}); |
|||
|
|||
KeyHelper.generatePreKey(1).then(function(preKey) { |
|||
console.log('preKey'); |
|||
console.log(preKey); |
|||
store.storePreKey(preKey.keyId, preKey.keyPair); |
|||
}); |
|||
|
|||
KeyHelper.generateSignedPreKey(identityKeyPair, keyId).then(function(signedPreKey) { |
|||
store.storeSignedPreKey(signedPreKey.keyId, signedPreKey.keyPair); |
|||
});*/ |
|||
|
|||
var ChatOmemo = { |
|||
generateBundle : async function() |
|||
{ |
|||
const identityKeyPair = await KeyHelper.generateIdentityKeyPair(); |
|||
const bundle = {}; |
|||
const identityKey = MovimUtils.arrayBufferToBase64(identityKeyPair.pubKey); |
|||
const deviceId = KeyHelper.generateRegistrationId(); |
|||
|
|||
bundle['identityKey'] = identityKey; |
|||
bundle['deviceId'] = deviceId; |
|||
/*this.save({ |
|||
'deviceId': deviceId, |
|||
'identityKeyPair': { |
|||
'privKey': MovimUtils.arrayBufferToBase64(identityKeyPair.privKey), |
|||
'pubKey': identityKey |
|||
}, |
|||
'identityKey': identityKey |
|||
});*/ |
|||
const signedPreKey = await KeyHelper.generateSignedPreKey(identityKeyPair, 0); |
|||
console.log(signedPreKey); |
|||
localStorage.setObject('signedPreKey', { |
|||
'privKey' : MovimUtils.arrayBufferToBase64(signedPreKey.keyPair.privKey), |
|||
'pubKey' : MovimUtils.arrayBufferToBase64(signedPreKey.keyPair.pubKey), |
|||
'signature' : MovimUtils.arrayBufferToBase64(signedPreKey.signature), |
|||
}); |
|||
|
|||
//_converse.omemo_store.storeSignedPreKey(signedPreKey);
|
|||
bundle['signedPreKey'] = { |
|||
'id': signedPreKey.keyId, |
|||
'publicKey': MovimUtils.arrayBufferToBase64(signedPreKey.keyPair.privKey), |
|||
'signature': MovimUtils.arrayBufferToBase64(signedPreKey.signature) |
|||
} |
|||
const keys = await Promise.all(MovimUtils.range(0, 5).map(id => KeyHelper.generatePreKey(id))); |
|||
//keys.forEach(k => _converse.omemo_store.storePreKey(k.keyId, k.keyPair));
|
|||
keys.forEach(k => { |
|||
localStorage.setObject('preKey' + k.keyId, { |
|||
'privKey' : MovimUtils.arrayBufferToBase64(k.keyPair.privKey), |
|||
'pubKey' : MovimUtils.arrayBufferToBase64(k.keyPair.pubKey), |
|||
}); |
|||
}); |
|||
const preKeys = keys.map(k => ({'id': k.keyId, 'key': MovimUtils.arrayBufferToBase64(k.keyPair.pubKey)})); |
|||
bundle['preKeys'] = preKeys; |
|||
|
|||
ChatOmemo_ajaxAnnounceBundle(bundle); |
|||
/*const devicelist = _converse.devicelists.get(_converse.bare_jid); |
|||
const device = await devicelist.devices.create({'id': bundle.deviceId, 'jid': _converse.bare_jid}, {'promise': true}); |
|||
const marshalled_keys = keys.map(k => ({'id': k.keyId, 'key': MovimUtils.arrayBufferToBase64(k.keyPair.pubKey)})); |
|||
bundle['prekeys'] = marshalled_keys; |
|||
device.save('bundle', bundle);*/ |
|||
} |
|||
} |
@ -0,0 +1,122 @@ |
|||
function ChatOmemoStorage() { |
|||
this.store = {}; |
|||
} |
|||
|
|||
ChatOmemoStorage.prototype = { |
|||
Direction: { |
|||
SENDING: 1, |
|||
RECEIVING: 2, |
|||
}, |
|||
|
|||
getIdentityKeyPair: function () { |
|||
return Promise.resolve(this.get('identityKey')); |
|||
}, |
|||
getLocalRegistrationId: function () { |
|||
return Promise.resolve(this.get('registrationId')); |
|||
}, |
|||
put: function (key, value) { |
|||
if (key === undefined || value === undefined || key === null || value === null) |
|||
throw new Error("Tried to store undefined/null"); |
|||
|
|||
localStorage.setObject(key, value); |
|||
}, |
|||
get: function (key, defaultValue) { |
|||
if (key === null || key === undefined) |
|||
throw new Error("Tried to get value for undefined/null key"); |
|||
if (key in localStorage) { |
|||
return localStorage.getObject(key); |
|||
} else { |
|||
return defaultValue; |
|||
} |
|||
}, |
|||
remove: function (key) { |
|||
if (key === null || key === undefined) |
|||
throw new Error("Tried to remove value for undefined/null key"); |
|||
|
|||
localStorage.removeItem(key); |
|||
//delete this.store[key];
|
|||
}, |
|||
|
|||
isTrustedIdentity: function (identifier, identityKey, direction) { |
|||
if (identifier === null || identifier === undefined) { |
|||
throw new Error("tried to check identity key for undefined/null key"); |
|||
} |
|||
if (!(identityKey instanceof ArrayBuffer)) { |
|||
throw new Error("Expected identityKey to be an ArrayBuffer"); |
|||
} |
|||
var trusted = this.get('identityKey' + identifier); |
|||
if (trusted === undefined) { |
|||
return Promise.resolve(true); |
|||
} |
|||
return Promise.resolve(util.toString(identityKey) === util.toString(trusted)); |
|||
}, |
|||
loadIdentityKey: function (identifier) { |
|||
if (identifier === null || identifier === undefined) |
|||
throw new Error("Tried to get identity key for undefined/null key"); |
|||
return Promise.resolve(this.get('identityKey' + identifier)); |
|||
}, |
|||
saveIdentity: function (identifier, identityKey) { |
|||
if (identifier === null || identifier === undefined) |
|||
throw new Error("Tried to put identity key for undefined/null key"); |
|||
|
|||
var address = new libsignal.SignalProtocolAddress.fromString(identifier); |
|||
|
|||
var existing = this.get('identityKey' + address.getName()); |
|||
this.put('identityKey' + address.getName(), identityKey) |
|||
|
|||
if (existing && util.toString(identityKey) !== util.toString(existing)) { |
|||
return Promise.resolve(true); |
|||
} else { |
|||
return Promise.resolve(false); |
|||
} |
|||
|
|||
}, |
|||
|
|||
/* Returns a prekeypair object or undefined */ |
|||
loadPreKey: function (keyId) { |
|||
var res = this.get('25519KeypreKey' + keyId); |
|||
if (res !== undefined) { |
|||
res = { pubKey: res.pubKey, privKey: res.privKey }; |
|||
} |
|||
return Promise.resolve(res); |
|||
}, |
|||
storePreKey: function (keyId, keyPair) { |
|||
return Promise.resolve(this.put('25519KeypreKey' + keyId, keyPair)); |
|||
}, |
|||
removePreKey: function (keyId) { |
|||
return Promise.resolve(this.remove('25519KeypreKey' + keyId)); |
|||
}, |
|||
|
|||
/* Returns a signed keypair object or undefined */ |
|||
loadSignedPreKey: function (keyId) { |
|||
var res = this.get('25519KeysignedKey' + keyId); |
|||
if (res !== undefined) { |
|||
res = { pubKey: res.pubKey, privKey: res.privKey }; |
|||
} |
|||
return Promise.resolve(res); |
|||
}, |
|||
storeSignedPreKey: function (keyId, keyPair) { |
|||
return Promise.resolve(this.put('25519KeysignedKey' + keyId, keyPair)); |
|||
}, |
|||
removeSignedPreKey: function (keyId) { |
|||
return Promise.resolve(this.remove('25519KeysignedKey' + keyId)); |
|||
}, |
|||
|
|||
loadSession: function (identifier) { |
|||
return Promise.resolve(this.get('session' + identifier)); |
|||
}, |
|||
storeSession: function (identifier, record) { |
|||
return Promise.resolve(this.put('session' + identifier, record)); |
|||
}, |
|||
removeSession: function (identifier) { |
|||
return Promise.resolve(this.remove('session' + identifier)); |
|||
}, |
|||
removeAllSessions: function (identifier) { |
|||
for (var id in this.store) { |
|||
if (id.startsWith('session' + identifier)) { |
|||
delete this.store[id]; |
|||
} |
|||
} |
|||
return Promise.resolve(); |
|||
} |
|||
}; |
Write
Preview
Loading…
Cancel
Save
Reference in new issue