BTC Certificate feature

Added the ability to register card content on the BTC blockchain in order to certify its existance/content
This commit is contained in:
Giulio Cesare Solaroli
2016-03-29 11:45:50 +02:00
parent f84d05240b
commit fbcd02dffd
102 changed files with 23275 additions and 8645 deletions

View File

@@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures');
Clipperz.PM.UI.Components.ExtraFeatures.DataExportClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataExport',
propTypes: {
// featureSet: React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']).isRequired,
// 'level': React.PropTypes.oneOf(['hide', 'info', 'warning', 'error']).isRequired

View File

@@ -25,7 +25,9 @@ refer to http://www.clipperz.com.
Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures');
Clipperz.PM.UI.Components.ExtraFeatures.DataImportClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport',
getInitialState: function() {
return {
'importContext': new Clipperz.PM.UI.ImportContext(this),

View File

@@ -25,6 +25,8 @@ refer to http://www.clipperz.com.
Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV');
Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.ColumnsClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.Columns',
getInitialState: function() {
return {

View File

@@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV');
Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.HiddenClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.Hidden',
getInitialState: function() {
return {
'hiddenFields': this.props.importContext.state('csvData.hiddenFields'),

View File

@@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV');
Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.LabelsClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.Labels',
getInitialState: function() {
return {
'useFirstRowAsLabels': this.props.importContext.state('csvData.useFirstRowAsLabels'),
@@ -57,7 +59,7 @@ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.LabelsClass = React.creat
var newState;
newState = this.state;
newState['labels'][columnIndex] = this.refs['csv-labels-input-' + columnIndex].getDOMNode().value;
newState['labels'][columnIndex] = this.refs['csv-labels-input-' + columnIndex].value;
this.setState(newState);
this.updateImportContextState();

View File

@@ -25,7 +25,9 @@ refer to http://www.clipperz.com.
Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV');
Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.NotesClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.Notes',
getInitialState: function() {
return {
'notesIndex': this.props.importContext.state('csvData.notesIndex'),

View File

@@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV');
Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.TitlesClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.Titles',
getInitialState: function() {
return {
'titleIndex': this.props.importContext.state('csvData.titleIndex'),

View File

@@ -27,6 +27,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures.DataImport');
Clipperz.PM.UI.Components.ExtraFeatures.DataImport.ImportClass = React.createClass({
//=========================================================================
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.Import',
importHandler: function (anEvent) {
var recordsToImport = this.props.importContext.state('recordsToImport');

View File

@@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures.DataImport');
Clipperz.PM.UI.Components.ExtraFeatures.DataImport.InputClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.Input',
getInitialState: function() {
return {
'inputString': this.props.importContext.inputString(),
@@ -46,7 +48,7 @@ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.InputClass = React.createClas
var jsonData;
var parsedInput;
var inputString = this.refs['input-textarea'].getDOMNode().value.trim();
var inputString = this.refs['input-textarea'].value.trim();
// this.props.importContext.setData(inputString);
result = {'inputString': inputString};
@@ -80,7 +82,7 @@ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.InputClass = React.createClas
var re = new RegExp('.*<textarea>(.*)<\/textarea>.*','g');
if (re.test(someHtml)) {
textarea = this.refs['input-textarea'].getDOMNode();
textarea = this.refs['input-textarea'];
textarea.innerHTML = someHtml.replace(re, '$1');
result = textarea.innerHTML;
} else {
@@ -208,17 +210,19 @@ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.InputClass = React.createClas
// http://enome.github.io/javascript/2014/03/24/drag-and-drop-with-react-js.html
// https://code.google.com/p/chromium/issues/detail?id=168387
// http://www.quirksmode.org/blog/archives/2009/09/the_html5_drag.html
anEvent.stopPropagation();
anEvent.preventDefault();
anEvent.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
},
handleTextareaChange: function () {
// var newInputString;
//
// newInputString = this.refs['input-textarea'].getDOMNode().value;
// newInputString = this.refs['input-textarea'].value;
// this.setState({'inputString': newInputString});
// this.props.importContext.setInputString(newInputString);
this.updateTextAreaContent(this.refs['input-textarea'].getDOMNode().value, false);
this.updateTextAreaContent(this.refs['input-textarea'].value, false);
},
//=========================================================================
@@ -247,7 +251,7 @@ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.InputClass = React.createClas
React.DOM.br({}),
React.DOM.a({
'className': 'button',
'onClick': MochiKit.Base.bind(function() { this.refs['upload-input'].getDOMNode().click() }, this),
'onClick': MochiKit.Base.bind(function() { this.refs['upload-input'].click() }, this),
}, "select it manually")
]),
React.DOM.div({'className': 'description'},

View File

@@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures.DataImport');
Clipperz.PM.UI.Components.ExtraFeatures.DataImport.PreviewClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.Preview',
getInitialState: function() {
var recordsToImport;
@@ -83,7 +85,7 @@ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.PreviewClass = React.createCl
//-------------------------------------------------------------------------
handleImportTagTextChange: function() {
var newTag = this.refs['importTagText'].getDOMNode().value;
var newTag = this.refs['importTagText'].value;
this.props.importContext.setState('importTag', newTag);
},

View File

@@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.DeleteAccount');
Clipperz.PM.UI.Components.ExtraFeatures.DeleteAccountClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DeleteAccount',
propTypes: {
// featureSet: React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']).isRequired,
// 'level': React.PropTypes.oneOf(['hide', 'info', 'warning', 'error']).isRequired
@@ -50,15 +52,15 @@ Clipperz.PM.UI.Components.ExtraFeatures.DeleteAccountClass = React.createClass({
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("DeleteAccount.handleDeleteAccount", {trace: false});
deferredResult.addCallback(this.props.userInfo['checkPassphraseCallback'], this.refs['passphrase'].getDOMNode().value);
deferredResult.addCallback(this.props.userInfo['checkPassphraseCallback'], this.refs['passphrase'].value);
deferredResult.addMethod(this, function(passCheck){
var username = this.refs['username'].getDOMNode().value;
var passphrase = this.refs['passphrase'].getDOMNode().value;
var username = this.refs['username'].value;
var passphrase = this.refs['passphrase'].value;
this.setState({
'username': (username != '') ? (username == this.props.userInfo['username']) ? 'valid' : 'invalid' : 'empty',
'passphrase': (passphrase != '') ? (passCheck) ? 'valid' : 'invalid' : 'empty',
'confirm': this.refs['confirm'].getDOMNode().checked,
'confirm': this.refs['confirm'].checked,
});
});
@@ -87,7 +89,7 @@ Clipperz.PM.UI.Components.ExtraFeatures.DeleteAccountClass = React.createClass({
React.DOM.input({'key':'passphrase', 'className': this.state['passphrase'], 'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase"}),
React.DOM.p({}, [
React.DOM.input({'key':'confirm', 'className':'confirmCheckbox', 'type':'checkbox', 'id':'deleteAccountConfirmCheckbox', 'name':'confirm', 'ref':'confirm'}),
React.DOM.label({'htmlFor':'deleteAccountConfirmCheckbox'}, "All my data will be permanently deleted. I understand that this action cannot be undone or cancelled.")
React.DOM.label({'htmlFor':'deleteAccountConfirmCheckbox'}, "All my data will be permanently deleted. I understand that this action cannot be undone or canceled.")
]),
]),
React.DOM.button({'key':'button', 'type':'submit', 'disabled':!this.shouldEnableDeleteAccountButton(), 'className':'button'}, "Delete my account")

View File

@@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures');
Clipperz.PM.UI.Components.ExtraFeatures.DevicePINClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DevicePIN',
propTypes: {
// featureSet: React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']).isRequired,
// 'level': React.PropTypes.oneOf(['hide', 'info', 'warning', 'error']).isRequired
@@ -59,7 +61,7 @@ Clipperz.PM.UI.Components.ExtraFeatures.DevicePINClass = React.createClass({
},
setFocus: function() {
this.refs['pinValue'].getDOMNode().focus();
this.refs['pinValue'].focus();
},
resetPIN: function() {

View File

@@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures');
Clipperz.PM.UI.Components.ExtraFeatures.OTPClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.OTP',
getInitialState: function() {
return {
// 'selectedOTPs': [],
@@ -82,7 +84,7 @@ Clipperz.PM.UI.Components.ExtraFeatures.OTPClass = React.createClass({
},
handleLabelSave: function (anOTP) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'changeOTPLabel', anOTP.reference(), this.state['otpLabel']);
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'changeOTPLabel', {'reference':anOTP.reference(), 'label':this.state['otpLabel']});
this.handleLabelCancel()
},

View File

@@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures');
Clipperz.PM.UI.Components.ExtraFeatures.PassphraseClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.Passphrase',
propTypes: {
},
@@ -44,18 +46,18 @@ Clipperz.PM.UI.Components.ExtraFeatures.PassphraseClass = React.createClass({
resetForm: function () {
this.setState(this.getInitialState());
this.refs['username'].getDOMNode().value = '';
this.refs['old-passphrase'].getDOMNode().value = '';
this.refs['new-passphrase'].getDOMNode().value = '';
this.refs['confirm-new-passphrase'].getDOMNode().value = '';
this.refs['confirm'].getDOMNode().checked = false;
this.refs['username'].value = '';
this.refs['old-passphrase'].value = '';
this.refs['new-passphrase'].value = '';
this.refs['confirm-new-passphrase'].value = '';
this.refs['confirm'].checked = false;
},
handleChangePassphrase: function(event) {
var newPassphrase;
event.preventDefault();
newPassphrase = this.refs['new-passphrase'].getDOMNode().value;
newPassphrase = this.refs['new-passphrase'].value;
this.resetForm();
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'changePassphrase', newPassphrase);
@@ -65,19 +67,19 @@ Clipperz.PM.UI.Components.ExtraFeatures.PassphraseClass = React.createClass({
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("Passphrase.handleFormChange", {trace: false});
deferredResult.addCallback(this.props.userInfo['checkPassphraseCallback'], this.refs['old-passphrase'].getDOMNode().value);
deferredResult.addCallback(this.props.userInfo['checkPassphraseCallback'], this.refs['old-passphrase'].value);
deferredResult.addMethod(this, function(passCheck){
var username = this.refs['username'].getDOMNode().value;
var oldPassphrase = this.refs['old-passphrase'].getDOMNode().value;
var newPassphrase = this.refs['new-passphrase'].getDOMNode().value;
var confirmNewPassphrase = this.refs['confirm-new-passphrase'].getDOMNode().value;
var username = this.refs['username'].value;
var oldPassphrase = this.refs['old-passphrase'].value;
var newPassphrase = this.refs['new-passphrase'].value;
var confirmNewPassphrase = this.refs['confirm-new-passphrase'].value;
this.setState({
'username': (username != '') ? [(username == this.props.userInfo['username']) ? 'valid' : 'invalid'] : 'empty',
'old-passphrase': (oldPassphrase != '') ? [(passCheck) ? 'valid' : 'invalid'] : 'empty',
'new-passphrase': (newPassphrase != '') ? 'valid' : 'empty',
'confirm-new-passphrase': (confirmNewPassphrase != '') ? [(confirmNewPassphrase == newPassphrase) ? 'valid' : 'invalid'] : 'empty',
'confirm': this.refs['confirm'].getDOMNode().checked,
'confirm': this.refs['confirm'].checked,
});
});

View File

@@ -0,0 +1,118 @@
/*
Copyright 2008-2015 Clipperz Srl
This file is part of Clipperz, the online password manager.
For further information about its features and functionalities please
refer to http://www.clipperz.com.
* Clipperz is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
* Clipperz is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU Affero General Public
License along with Clipperz. If not, see http://www.gnu.org/licenses/.
*/
"use strict";
Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures');
Clipperz.PM.UI.Components.ExtraFeatures.PlanClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.Plan',
propTypes: {
},
formatQuota: function (aValue) {
return filesize(aValue);
},
percentageOfUsedAttachmentQuota: function () {
return this.props['accountInfo']['attachmentQuota']['used'] / this.props['accountInfo']['attachmentQuota']['available'] * 100;
},
//=========================================================================
renderCertificateIcons: function () {
var result;
var totalCertificates;
var publishedCertificates;
var requestedCertificates;
var availableCertificates;
// var i, c;
// result = [];
totalCertificates = this.props['accountInfo']['certificateQuota']['totalNumber'];
publishedCertificates = this.props['accountInfo']['certificateQuota']['used']['published'];
requestedCertificates = this.props['accountInfo']['certificateQuota']['used']['requested'];
availableCertificates = totalCertificates - (publishedCertificates + requestedCertificates);
// c = totalCertificates;
// for (i=0; i<c; i++) {
// var className;
//
// if (i < publishedCertificates) {
// className = 'published';
// } else if (i < (publishedCertificates + requestedCertificates)) {
// className = 'requested';
// } else {
// className = 'available'
// };
// result.push(React.DOM.li({'className':className}, "certificate"));
// }
return React.DOM.ul({}, [
React.DOM.li({'className':'published'}, "published: " + ((publishedCertificates > 0) ? publishedCertificates : '-')),
React.DOM.li({'className':'requested'}, "requested: " + ((requestedCertificates > 0) ? requestedCertificates : '-')),
React.DOM.li({'className':'available'}, "available: " + ((availableCertificates > 0) ? availableCertificates : '-')),
]);
},
render: function () {
return React.DOM.div({className:'extraFeature plan'}, [
React.DOM.div({'className':'header'}, [
React.DOM.h1({}, "Current plan"),
]),
React.DOM.div({'className': 'content'}, [
React.DOM.div({'className': 'attachments'}, [
React.DOM.h2({}, "Attachments quota"),
React.DOM.dl({}, [
React.DOM.dt({}, [
React.DOM.span({'className':'key'}, 'available')
]), React.DOM.dd({}, this.formatQuota(this.props['accountInfo']['attachmentQuota']['available'])),
React.DOM.dt({}, [
React.DOM.span({'className':'key'}, 'used'),
]), React.DOM.dd({}, this.formatQuota(this.props['accountInfo']['attachmentQuota']['used'])),
]),
React.DOM.div({'className': 'progressBar'}, [
React.DOM.span({'className': 'progress', 'style': {'width': this.percentageOfUsedAttachmentQuota() + '%'}})
// MochiKit.Style.setElementDimensions(this.getElement('progress'), {'w': aProgressPercentage}, '%');
])
]),
React.DOM.div({'className': 'certificates'}, [
React.DOM.h2({}, "Certificates"),
this.renderCertificateIcons(),
]),
React.DOM.div({'className': 'upgrade'}, [
React.DOM.button({'className':'button disabled', 'type':'submit'}, "upgrade")
])
])
]);
},
//=========================================================================
});
Clipperz.PM.UI.Components.ExtraFeatures.Plan = React.createFactory(Clipperz.PM.UI.Components.ExtraFeatures.PlanClass);

View File

@@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures');
Clipperz.PM.UI.Components.ExtraFeatures.PreferencesClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.Preferences',
getInitialState: function() {
return {
'editedPreferences': new Clipperz.KeyValueObjectStore()
@@ -66,7 +68,7 @@ Clipperz.PM.UI.Components.ExtraFeatures.PreferencesClass = React.createClass({
checkboxClick: function (aRef) {
return MochiKit.Base.bind(function (anEvent) {
// console.log("CHECKBOX CLICK", this, this.refs, this.refs[aRef]);
this.refs[aRef].getDOMNode().click();
this.refs[aRef].click();
}, this);
},