Initial Checkin
This commit is contained in:
commit
a25cf5f176
9 changed files with 286 additions and 0 deletions
8
background.js
Normal file
8
background.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
function check_first_install() {
|
||||
if (localStorage.getItem('first_install_ran'))
|
||||
return;
|
||||
|
||||
localStorage.setItem('first_install_ran', 1);
|
||||
chrome.tabs.create({url: "options.html"});
|
||||
}
|
||||
check_first_install();
|
115
helpers.js
Normal file
115
helpers.js
Normal file
|
@ -0,0 +1,115 @@
|
|||
/************************************************
|
||||
*** Utilities to store data in local storage ***
|
||||
************************************************/
|
||||
var storage = {};
|
||||
|
||||
storage.putEncrypted = function(key, value) {
|
||||
//TODO
|
||||
localStorage.setItem("e" + key, value);
|
||||
}
|
||||
|
||||
storage.getEncrypted = function(key, defaultValue) {
|
||||
//TODO
|
||||
var value = localStorage.getItem("e" + key);
|
||||
if (value === null)
|
||||
return defaultValue;
|
||||
return value;
|
||||
}
|
||||
|
||||
storage.putUnencrypted = function(key, value) {
|
||||
localStorage.setItem("u" + key, value);
|
||||
}
|
||||
|
||||
storage.getUnencrypted = function(key, defaultValue) {
|
||||
var value = localStorage.getItem("u" + key);
|
||||
if (value === null)
|
||||
return defaultValue;
|
||||
return value;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
*** Utilities to communicate with the server ***
|
||||
************************************************/
|
||||
var URL_BASE = "http://textsecure-test.herokuapp.com";
|
||||
var URL_CALLS = {};
|
||||
URL_CALLS['devices'] = "/v1/devices";
|
||||
URL_CALLS['keys'] = "/v1/keys";
|
||||
|
||||
/**
|
||||
* REQUIRED PARAMS:
|
||||
* call: URL_CALLS entry
|
||||
* httpType: POST/GET/PUT/etc
|
||||
* success_callback: function(response object) called on success
|
||||
* error_callback: function(http status code = -1 or != 200) called on failure
|
||||
* OPTIONAL PARAMS:
|
||||
* urlParameters: crap appended to the url (probably including a leading /)
|
||||
* user: user name to be sent in a basic auth header
|
||||
* password: password to be sent in a basic auth header
|
||||
* jsonData: JSON data sent in the request body
|
||||
*/
|
||||
function doAjax(param) {
|
||||
if (param.urlParameters === undefined)
|
||||
param.urlParameters = "";
|
||||
$.ajax(URL_BASE + URL_CALLS[param.call] + param.urlParameters, {
|
||||
type: param.httpType,
|
||||
data: param.jsonData,
|
||||
beforeSend: function(xhr) {
|
||||
if (param.user !== undefined && param.password !== undefined)
|
||||
xhr.setRequestHeader("Authorization", "Basic " + btoa(param.user + ":" + param.password));
|
||||
},
|
||||
success: function(response, textStatus, jqXHR) {
|
||||
param.success_callback(response);
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
var code = jqXHR.status;
|
||||
if (code > 999 || code < 100)
|
||||
code = -1;
|
||||
param.error_callback(code);
|
||||
},
|
||||
cache: false
|
||||
});
|
||||
}
|
||||
|
||||
/*******************************************
|
||||
*** Utilities to manage keys/randomness ***
|
||||
*******************************************/
|
||||
function getRandomBytes(size) {
|
||||
//TODO: Better random (https://www.grc.com/r&d/js.htm?
|
||||
try {
|
||||
var array = new Uint8Array(size);
|
||||
window.crypto.getRandomValues(array);
|
||||
return array;
|
||||
} catch (err) {
|
||||
//TODO: ummm...wat?
|
||||
}
|
||||
}
|
||||
|
||||
function getNewPubKey(keyName) {
|
||||
//TODO
|
||||
var pubKey = "BRTJzsHPUWRRBxyo5MoaBRidMk2fwDlfqvU91b6pzbED";
|
||||
var privKey = "";
|
||||
storage.putEncrypted("pubKey" + keyName, pubKey);
|
||||
storage.putEncrypted("privKey" + keyName, privKey);
|
||||
return pubKey;
|
||||
}
|
||||
|
||||
function getExistingPubKey(keyName) {
|
||||
return storage.getEncrypted("pubKey" + keyName);
|
||||
}
|
||||
|
||||
function generateKeys() {
|
||||
var identityKey = getExistingPubKey("identityKey");
|
||||
if (identityKey === undefined)
|
||||
identityKey = getNewPubKey("identityKey");
|
||||
|
||||
var keyGroupId = storage.getEncrypted("lastKeyGroupId", -1) + 1;
|
||||
storage.putEncrypted("lastKeyGroupId", keyGroupId);
|
||||
|
||||
var keys = {};
|
||||
keys.keys = [];
|
||||
for (var i = 0; i < 100; i++)
|
||||
keys.keys[i] = {keyId: i, publicKey: getNewPubKey("key" + keyGroupId + i), identityKey: identityKey};
|
||||
// 0xFFFFFF == 16777215
|
||||
keys.lastResortKey = {keyId: 16777215, publicKey: getNewPubKey("lastResortKey" + keyGroupId), identityKey: identityKey};
|
||||
return keys;
|
||||
}
|
BIN
icon.png
Normal file
BIN
icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
6
jquery.js
vendored
Normal file
6
jquery.js
vendored
Normal file
File diff suppressed because one or more lines are too long
23
manifest.json
Normal file
23
manifest.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"manifest_version": 2,
|
||||
|
||||
"name": "TextSecure",
|
||||
"description": "Secure texting ",
|
||||
"version": "0.0.1",
|
||||
"offline_enabled": false,
|
||||
|
||||
"icons": { "128": "icon.png" },
|
||||
|
||||
"browser_action": {
|
||||
"default_icon": {
|
||||
"19": "icon.png"
|
||||
},
|
||||
"default_popup": "popup.html"
|
||||
},
|
||||
|
||||
"background": {
|
||||
"scripts": ["background.js"]
|
||||
},
|
||||
|
||||
"options_page": "options.html"
|
||||
}
|
19
options.css
Normal file
19
options.css
Normal file
|
@ -0,0 +1,19 @@
|
|||
* {
|
||||
font-family: Ubuntu, Segoe, 'Lucidia Grande', sans-serif;
|
||||
}
|
||||
|
||||
html {
|
||||
margin: 12px 0 0 100px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 14pt;
|
||||
font-weight: normal;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 12pt;
|
||||
font-weight: normal;
|
||||
}
|
26
options.html
Normal file
26
options.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>TextSecure Options</title>
|
||||
<link rel="stylesheet" href="options.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>TextSecure</h1>
|
||||
<div id="init-setup" style="display: none;">
|
||||
<h2>Welcome to TextSecure. To get startet please get a 6-digit setup code from your phone and enter it below.</h2>
|
||||
Phone number: <input type="text" title="Enter the phone number which you've registered TextSecure with." size="8" id="number" />
|
||||
Code: <input type="text" pattern="[0-9]{3}-?[0-9]{3}" title="Enter the 6-didgit verificaion code displayed on your phone." size="8" id="code" /><br>
|
||||
<button id="init-go" >Sync</button>
|
||||
</div>
|
||||
<div id="verify" style="display: none;">
|
||||
<div id="verify1">Verifying number and setup code...<span id="verify1done"></span></div>
|
||||
<div id="verify2">Generating keys...<span id="verify2done"></span></div>
|
||||
<div id="verify3">Registering...<span id="verify3done"></span></div>
|
||||
</div>
|
||||
<div id="setup-complete" style="display: none;">
|
||||
<h2>You are now registered on TextSecure with number <span id="complete-number"></span></h2>
|
||||
</div>
|
||||
<script type="text/javascript" src="jquery.js"></script>
|
||||
<script type="text/javascript" src="helpers.js"></script>
|
||||
<script type="text/javascript" src="options.js"></script>
|
||||
</body>
|
||||
</html>
|
76
options.js
Normal file
76
options.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
function codeMatches() {
|
||||
var match = $('#code').val().match(/[0-9]{3}-?[0-9]{3}/g)
|
||||
return match != null && match.length == 1 && match[0] == $('#code').val();
|
||||
}
|
||||
|
||||
function numberMatches() {
|
||||
return $('#number').value().replace(/\D/g, '').length == 10;
|
||||
}
|
||||
|
||||
$('#code').on('change', function() {
|
||||
if (!codeMatches())
|
||||
$('#code').attr('style', 'background-color:#ff6666;');
|
||||
else
|
||||
$('#code').attr('style', '');
|
||||
});
|
||||
|
||||
$('#number').on('change', function() {
|
||||
if (!numberMatches())
|
||||
$('#number').attr('style', 'background-color:#ff6666;');
|
||||
else
|
||||
$('#number').attr('style', '');
|
||||
}
|
||||
|
||||
$('#init-go').click(function() {
|
||||
if (codeMatches() && numberMatches()) {
|
||||
var signaling_key = getRandomBytes(32 + 20);
|
||||
var password = getRandomBytes(16);
|
||||
var number = $('#number').value().replace(/\D/g, '');
|
||||
|
||||
$('#init-setup').hide();
|
||||
$('#verify1done').html('');
|
||||
$('#verify2done').html('');
|
||||
$('#verify3done').html('');
|
||||
$('#verify').show();
|
||||
|
||||
doAjax({call: 'devices', httpType: 'PUT', urlParameters: '/' + $('#code').val(), success_callback: function(response) {
|
||||
$('#verify1done').html('done');
|
||||
var keys = generateKeys();
|
||||
$('#verify2done').html('done');
|
||||
doAjax({call: 'keys', httpType: 'PUT', user: number + "." + response, password: password,
|
||||
jsonData: keys, success_callback: function(response) {
|
||||
$('#complete-number').html('');
|
||||
$('#verify').hide();
|
||||
$('#setup-complete').show();
|
||||
}, error_callback: function(code) {
|
||||
alert(code); //TODO
|
||||
}
|
||||
});
|
||||
storage.putEncrypted('signaling_key', signaling_key);
|
||||
storage.putEncrypted('login_password', password);
|
||||
}, error_callback: function(code) {
|
||||
var error;
|
||||
switch(code) {
|
||||
case 403:
|
||||
error = "Invalid code, please try again.";
|
||||
break;
|
||||
case -1:
|
||||
error = "Error connecting to server, please check your network connection.";
|
||||
break;
|
||||
default:
|
||||
error = "Unknown error, please try again later.";
|
||||
console.log("Got error code " + code);
|
||||
}
|
||||
alert(error); //TODO
|
||||
}, user: number, password: password,
|
||||
jsonData: {signalingKey: btoa(String.fromCharCode.apply(null, signaling_key)), supportsSms: false, fetchesMessages: true}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (storage.getUnencrypted("number_id") === undefined) {
|
||||
$('#init-setup').show();
|
||||
} else {
|
||||
$('#complete-number').html(storage.getUnencrypted("number_id"));
|
||||
$('#setup-complete').show();
|
||||
}
|
13
popup.html
Normal file
13
popup.html
Normal file
|
@ -0,0 +1,13 @@
|
|||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="jquery-2.0.3.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a onclick="$('#inbox').style('display: block;'); $('#send').style('display: none;')">Inbox</a>
|
||||
<a onclick="$('#inbox').style('display: none;'); $('#send').style('display: block;')">Send</a>
|
||||
<div id="inbox">
|
||||
|
||||
</div>
|
||||
<div id="send" style="display:none;"></div>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue