Commit d7ecee20 authored by Adrien Dorsaz's avatar Adrien Dorsaz

options + main + client: don't use storage.local to store confidential informations

As advised in the documentation:
https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/storage/local

Pending of resolution for bug #1324919 "Land logins API":
https://bugzilla.mozilla.org/show_bug.cgi?id=1324919
parent 7c93100c
......@@ -36,7 +36,7 @@
"password-placeholder": {
"description": "Placeholder used to explain the password field should be filled only to set or update it.",
"message": "Fill password only to set or update it."
"message": ""
},
"websocket-label": {
......@@ -59,9 +59,14 @@
"message": "optional"
},
"save-start": {
"description": "Label for button Save and Start",
"message": "Save and start"
"why-no-remember-authentication": {
"description": "Explain why the extension won't remember credentials",
"message": "Unfortunately, there's no way in current Firefox extensions APIs to store confidential informations. So you'll need to login every time."
},
"connect": {
"description": "Label for connect to service button.",
"message": "Connect"
},
"first-run-welcome": {
......
......@@ -5,6 +5,7 @@ fieldset
grid-gap: 0.4rem;
margin: 0 0 0.4rem 0;
padding: 0.4rem;
vertical-align: middle;
}
label
......@@ -17,10 +18,35 @@ input
grid-column: 1;
}
.note {
display: grid;
grid-template-columns: 1fr;
grid-gap: 0.5rem;
padding: 0.5rem;
margin:0.5rem auto;
vertical-align: middle;
border: 1px #0670cc solid;
border-radius: 0.5rem;
width: 95%;
}
.note > div
{
grid-column: 1;
}
.note > div:first-child
{
color: #0670cc;
font-size: 2.5rem;
font-weight: bold;
text-align: center;
}
.explain
{
border-bottom: 1px dashed gray;
font-size : 0.8rem;
font-size : 0.9rem;
text-decoration: underline dotted;
}
.explain:hover
......@@ -32,17 +58,11 @@ input
{
fieldset
{
display: grid;
grid-template-columns: 11rem 1fr;
grid-gap: 1rem;
vertical-align: middle;
padding: 1rem;
grid-template-columns: 12rem 1fr;
}
label
{
text-align: right;
line-height: 2.5rem;
grid-column: 1 / 2;
}
......@@ -50,4 +70,19 @@ input
{
grid-column: 2 / 2;
}
.note {
grid-template-columns: 2rem 1fr;
grid-gap: 1rem;
}
.note > div
{
grid-column: 2 / 2;
}
.note > div:first-child{
grid-column: 1 / 2;
}
}
......@@ -54,10 +54,16 @@
</input>
</fieldset>
<div class="note">
<div></div>
<div>{{why-no-remember-authentication}}</div>
</div>
<button
type="submit"
class="browser-style default">
{{save-start}}
{{connect}}
</button>
</form>
</script>
......
function saveOptions(e) {
function connect(e) {
e.preventDefault();
function storePassword(hash) {
browser.storage.local.set({
password: hash
});
}
// Get jid
// TODO validate input, even if browser should check it's at least formated as mail
let jid = document.querySelector("#jid").value;
function digestError(error) {
console.log('options: error on computing password hash: ' + error);
}
// Get password
let password = document.querySelector("#password").value;
// Save new password if required
let passwordInput = document.querySelector("#password");
if (passwordInput && passwordInput.value !== '') {
// TODO Currently, we only implement PLAIN authentication, so we need PLAIN password
//let bufferPassword = new TextEncoder("utf-8").encode(passwordInput.value);
//crypto.subtle.digest('SHA-512', bufferPassword)
// .then(storePassword, digestError);
storePassword(passwordInput.value);
// Empty password field to be coherent with the placeholder
passwordInput.value = null;
}
// Save jid
browser.storage.local.set({
jid: document.querySelector("#jid").value
});
// Get WebSocket URL
let websocketURL = document.querySelector("#websocket").value;
// Try to connect
browser.runtime.sendMessage({
'from': 'options',
'subject': 'connect'
'subject': 'connect',
'jid': jid,
'password': password,
'websocketURL': websocketURL
});
}
function renderForm() {
let optionForm = Mustache.render(template, optionStrings);
document.querySelector("#target").innerHTML = optionForm;
document.querySelector("form").addEventListener("submit", saveOptions);
}
function restoreOptions() {
function setJidInput(result) {
optionStrings['jid'] = result.jid;
}
let getJid = browser.storage.local.get("jid");
getJid.then(setJidInput).then(renderForm);
}
// Render the page
let optionStrings = {
'authenticate': '',
......@@ -64,7 +32,8 @@ let optionStrings = {
'websocket-placeholder': '',
'websocket-help': '',
'optional': '',
'save-start': ''
'why-no-remember-authentication': '',
'connect': ''
}
for (const string of Object.keys(optionStrings)) {
......@@ -73,5 +42,7 @@ for (const string of Object.keys(optionStrings)) {
let template = document.querySelector("#form").innerHTML;
// Add logic to the form
document.addEventListener("DOMContentLoaded", restoreOptions);
Mustache.parse(template);
document.querySelector("#target").innerHTML = Mustache.render(template, optionStrings);
document.querySelector("form").addEventListener("submit", connect);
console.log('Welcome to XMPP-Pane main background script.');
retrieveConfig = function () {
retrieveConfig = function (jid, password, websocketURL) {
return new Promise((resolve, reject) => {
let config = {};
function setJid(localStorage) {
if (jid) {
config.jid = jid;
config.fulljid = null;
let splitedJid = config.jid.split('@');
config.localpart = splitedJid[0];
config.domainpart = splitedJid[1];
if (localStorage.jid) {
config.jid = localStorage.jid;
config.fulljid = null;
let splitedJid = config.jid.split('@');
config.localpart = splitedJid[0];
config.domainpart = splitedJid[1];
console.log('xmpp-pane-main: jid: ' + config.jid);
console.log('xmpp-pane-main: local part: ' + config.localpart);
console.log('xmpp-pane-main: domain part: ' + config.domainpart);
}
console.log('xmpp-pane-main: jid: ' + config.jid);
console.log('xmpp-pane-main: local part: ' + config.localpart);
console.log('xmpp-pane-main: domain part: ' + config.domainpart);
}
function setPassword(localStorage) {
if (localStorage.password) {
config.password = localStorage.password;
console.log('xmpp-pane-main: local storage found password.');
}
if (password) {
config.password = password;
console.log('xmpp-pane-main: found password.');
}
function onError(error) {
console.log('xmpp-pane-main: error:' + error);
reject(error);
if (websocketURL) {
config.websocketURL = websocketURL;
}
else {
config.websocketURL = null;
}
let getJid = browser.storage.local.get("jid");
let getPassword = browser.storage.local.get("password");
getJid.then(setJid, onError)
.then(getPassword.then(setPassword, onError)
.then(() => {
if (config.jid
&& config.localpart
&& config.domainpart
&& config.password) {
config.xmllang = browser.i18n.getUILanguage();
resolve(config);
}
else {
reject("xmpp-pane-main: Some configuration hasn't been found, please configure xmpp-pane first.");
}
}));
if (config.jid
&& config.localpart
&& config.domainpart
&& config.password) {
config.xmllang = browser.i18n.getUILanguage();
resolve(config);
}
else {
reject("xmpp-pane-main: Some configuration hasn't been found, please configure xmpp-pane first.");
}
});
};
......@@ -58,20 +48,16 @@ xmppClientListener = function (message, sender, sendResponse) {
switch (message.subject) {
case 'isConfigured':
asynchroneResponse = true;
retrieveConfig()
.then(
(config) => {
sendResponse({
configured: true
});
},
(error) => {
sendResponse({
configured: false
});
}
);
if (xmppPaneClient) {
sendResponse({
configured: true
});
}
else {
sendResponse({
configured: false
});
}
break;
case 'isConnected':
......@@ -105,7 +91,7 @@ xmppClientListener = function (message, sender, sendResponse) {
case 'connect':
asynchroneResponse = true;
retrieveConfig()
retrieveConfig(message.jid, message.password, message.websocketURL)
.then(
(_config) => {
xmppPaneClient = new Client(_config);
......
......@@ -24,6 +24,9 @@ class Client {
this.password = _config.password;
delete this.config.password;
// optional websocketURL
this.websocketURL = _config.websocketURL;
// DOM toolbox
this.dom = document.implementation.createDocument(null, null);
this.domParser = new DOMParser();
......@@ -177,21 +180,26 @@ class Client {
let xmppClient = this;
// First look on secure connection for websocket URL
let xrdURL = 'https://' + this.config.domainpart + '/.well-known/host-meta';
fetch(xrdURL)
.then(function (xrdResponse) {
return xrdResponse.text();
})
.then(xrdFindWebsocketURL, function (error) {
let xrdURL = 'http://' + xmppClient.config.domainpart + '/.well-known/host-meta';
return fetch(xrdUrl)
.then(function (xrdResponse) {
return xrdResponse.text();
});
})
.then(handshake);
if (this.websocketURL) {
handshake(this.websocketURL)
}
else {
// First look on secure connection for websocket URL
let xrdURL = 'https://' + this.config.domainpart + '/.well-known/host-meta';
fetch(xrdURL)
.then(function (xrdResponse) {
return xrdResponse.text();
})
.then(xrdFindWebsocketURL, function (error) {
let xrdURL = 'http://' + xmppClient.config.domainpart + '/.well-known/host-meta';
return fetch(xrdUrl)
.then(function (xrdResponse) {
return xrdResponse.text();
});
})
.then(handshake);
}
});
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment