BTC Certificate feature

Added the ability to register card content on the BTC blockchain in order to certify its existance/content
master-GE
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

@ -77,3 +77,33 @@ If you want to add other JS files you will have to include the reference to the
### SCSS files ### SCSS files
Any change to the SCSS files (as long as they are included directly or indirectly by clipperz.scss) will be visible as soon as you compile `scss/clipperz.scss` and reload the page on the browser. If you are using LiveReload, you can configure it to compile all files and reload the browser whenever you save any changes. Any change to the SCSS files (as long as they are included directly or indirectly by clipperz.scss) will be visible as soon as you compile `scss/clipperz.scss` and reload the page on the browser. If you are using LiveReload, you can configure it to compile all files and reload the browser whenever you save any changes.
# bitcoinJS-lib
## bitcoinJS-lib + bip32-utils + bip32-wallet -> browserify
> npm install bitcoinjs-lib
> npm install bip32-utils
> npm install bip32-wallet
> browserify Workarea/clipperz/gcsolaroli\@bitbucket/password-manager/frontend/delta/js/bitcoinjs-lib/npm.js -s bitcoin > Workarea/clipperz/gcsolaroli\@bitbucket/password-manager/frontend/delta/js/bitcoinjs-lib/bitcoinjs-lib-2.1.4.js
## bitcoinJS-lib raw
> browserify -r bitcoinjs-lib:bigi -s bitcoin -d > Workarea/clipperz/gcsolaroli\@bitbucket/password-manager/frontend/delta/js/bitcoinjs-lib/bitcoinjs-lib-2.1.4.js
## BigInteger
> npm install bigi@1.4.0
> browserify -r bigi -s BigInteger > Workarea/clipperz/gcsolaroli\@bitbucket/password-manager/frontend/delta/js/bitcoinjs-lib/bigi-1.4.0.js
## bops-browser
> npm install bops-browser
> browserify -r bops-browser -s bops > Workarea/clipperz/gcsolaroli\@bitbucket/password-manager/frontend/delta/js/bops-browser/bops-browser-0.6.0.js
## buffer
> npm buffer
> browserify -r buffer -s buffer > Workarea/clipperz/gcsolaroli\@bitbucket/password-manager/frontend/delta/js/buffer/buffer-4.3.0.js
## custom browserify packaging
> npm install bitcoinjs-lib@2.2.0
> browserify Workarea/clipperz/gcsolaroli\@bitbucket/password-manager/frontend/delta/js/npm/config.js -s npm > Workarea/clipperz/gcsolaroli\@bitbucket/password-manager/frontend/delta/js/npm/npm.js

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,138 @@
{ {
"IcoMoonType": "selection", "IcoMoonType": "selection",
"icons": [ "icons": [
{
"icon": {
"paths": [
"M108.018 534.899l148.392 76.747h576.168l-190.68-98.62h-385.488l-208.41-107.792v98.62l7.467 3.858z",
"M48.001 63.785v242.833l208.41 107.788h576.168l-536.16-277.295h593.28v768.365h-768.387v-166.462l135.098 69.865h576.168l-207.951-107.554h-368.217l-208.41-107.799v385.279h915.005v-915.020z"
],
"attrs": [],
"isMulticolor": false,
"grid": 0,
"tags": [
"CLIPPERZ_SOLO_LOGO-nero"
],
"width": 1024
},
"attrs": [],
"properties": {
"order": 42,
"id": 0,
"prevSize": 32,
"code": 59650,
"name": "CLIPPERZ_SOLO_LOGO-nero",
"ligatures": "clipperz"
},
"setIdx": 0,
"setId": 13,
"iconIdx": 0
},
{
"icon": {
"paths": [
"M786.286 512l78.857 77.143q17.143 16 11.429 40-6.857 23.429-29.714 29.143l-107.429 27.429 30.286 106.286q6.857 23.429-10.857 40-16.571 17.714-40 10.857l-106.286-30.286-27.429 107.429q-5.714 22.857-29.143 29.714-6.857 1.143-10.857 1.143-17.714 0-29.143-12.571l-77.143-78.857-77.143 78.857q-16 17.143-40 11.429-23.429-6.286-29.143-29.714l-27.429-107.429-106.286 30.286q-23.429 6.857-40-10.857-17.714-16.571-10.857-40l30.286-106.286-107.429-27.429q-22.857-5.714-29.714-29.143-5.714-24 11.429-40l78.857-77.143-78.857-77.143q-17.143-16-11.429-40 6.857-23.429 29.714-29.143l107.429-27.429-30.286-106.286q-6.857-23.429 10.857-40 16.571-17.714 40-10.857l106.286 30.286 27.429-107.429q5.714-23.429 29.143-29.143 23.429-6.857 40 10.857l77.143 79.429 77.143-79.429q16.571-17.143 40-10.857 23.429 5.714 29.143 29.143l27.429 107.429 106.286-30.286q23.429-6.857 40 10.857 17.714 16.571 10.857 40l-30.286 106.286 107.429 27.429q22.857 5.714 29.714 29.143 5.714 24-11.429 40z"
],
"attrs": [],
"isMulticolor": false,
"width": 878,
"tags": [
"certificate"
],
"grid": 0
},
"attrs": [],
"properties": {
"order": 1,
"id": 0,
"prevSize": 32,
"code": 59648,
"name": "certificate",
"ligatures": "certificate"
},
"setIdx": 2,
"setId": 11,
"iconIdx": 0
},
{
"icon": {
"paths": [
"M2.259 734.824h279.462v286.917h-279.462v-286.917z",
"M2.259 2.259h279.462v286.917h-279.462v-286.917z",
"M2.259 368.519h279.462v286.917h-279.462v-286.917z"
],
"width": 284,
"grid": 0,
"tags": [
"commands"
],
"attrs": []
},
"attrs": [],
"properties": {
"order": 18,
"id": 1,
"prevSize": 32,
"code": 58899,
"name": "commands",
"ligatures": "commands"
},
"setIdx": 8,
"setId": 4,
"iconIdx": 0
},
{
"icon": {
"paths": [
"M667.586 345.635v-338.544h-268.055v338.544l-299.967-121.263-90.486 257.986 310.037 104.527-198.134 262.808 224.514 164.237 184.802-279.685 203.382 279.685 221.11-164.237-203.382-262.808 319.397-107.080-90.486-257.986zM1220.574 2319.317z"
],
"width": 1080,
"grid": 0,
"tags": [
"logo"
],
"attrs": []
},
"attrs": [],
"properties": {
"order": 4,
"id": 0,
"prevSize": 32,
"code": 58884,
"name": "logo",
"ligatures": "qibberz"
},
"setIdx": 8,
"setId": 4,
"iconIdx": 1
},
{
"icon": {
"paths": [
"M429.696 257.6c54.88 0 68.608 27.424 105.152 22.848 36.576-4.576 4.576-68.576-27.424-114.272s-105.12-22.848-160 9.152c-54.848 32-346.272 209.152-346.272 209.152h254.848c0-0.032 118.848-126.88 173.696-126.88zM0 417.568v416c0 35.328 28.64 64 64 64 0 0 246.72 0 514.656 0 48.064 0 92-149.344 141.344-149.344 42.848 0 75.072 149.344 117.312 149.344 284.576 0 538.656 0 538.656 0 35.36 0 64.032-28.672 64.032-64v-416h-1440zM576 705.6c0 52.992-43.008 96-96 96h-288c-53.024 0-96-43.008-96-96v-96c0-53.024 42.976-96 96-96h288c52.992 0 96 42.976 96 96v96zM1344 705.6c0 52.992-43.008 96-96 96h-288c-53.024 0-96-43.008-96-96v-96c0-53.024 42.976-96 96-96h288c52.992 0 96 42.976 96 96v96zM905.12 280.448c36.576 4.576 50.272-22.848 105.152-22.848 54.848 0 173.728 126.848 173.728 126.848h254.848c0 0-291.424-177.152-346.272-209.152-54.88-32-128-54.848-160-9.152s-64 109.728-27.456 114.304z"
],
"attrs": [],
"isMulticolor": false,
"width": 1440,
"tags": [
"3d glasses",
"glasses"
],
"grid": 32
},
"attrs": [],
"properties": {
"order": 1,
"id": 0,
"prevSize": 32,
"code": 59649,
"name": "3dglasses",
"ligatures": "preview"
},
"setIdx": 1,
"setId": 12,
"iconIdx": 0
},
{ {
"icon": { "icon": {
"paths": [ "paths": [
@ -26,7 +158,7 @@
"name": "log-out", "name": "log-out",
"ligatures": "logout" "ligatures": "logout"
}, },
"setIdx": 0, "setIdx": 3,
"setId": 10, "setId": 10,
"iconIdx": 0 "iconIdx": 0
}, },
@ -55,7 +187,7 @@
"name": "mail", "name": "mail",
"ligatures": "email" "ligatures": "email"
}, },
"setIdx": 8, "setIdx": 11,
"setId": 0, "setId": 0,
"iconIdx": 4 "iconIdx": 4
}, },
@ -80,7 +212,7 @@
"name": "paperclip", "name": "paperclip",
"ligatures": "attachment" "ligatures": "attachment"
}, },
"setIdx": 8, "setIdx": 11,
"setId": 0, "setId": 0,
"iconIdx": 8 "iconIdx": 8
}, },
@ -106,7 +238,7 @@
"name": "popup", "name": "popup",
"ligatures": "url, direct login" "ligatures": "url, direct login"
}, },
"setIdx": 8, "setIdx": 11,
"setId": 0, "setId": 0,
"iconIdx": 35 "iconIdx": 35
}, },
@ -132,7 +264,7 @@
"name": "plus", "name": "plus",
"ligatures": "add new field, create new OTP" "ligatures": "add new field, create new OTP"
}, },
"setIdx": 8, "setIdx": 11,
"setId": 0, "setId": 0,
"iconIdx": 125 "iconIdx": 125
}, },
@ -160,7 +292,7 @@
"name": "cross", "name": "cross",
"ligatures": "remove field, remove tag, remove OTP" "ligatures": "remove field, remove tag, remove OTP"
}, },
"setIdx": 8, "setIdx": 11,
"setId": 0, "setId": 0,
"iconIdx": 126 "iconIdx": 126
}, },
@ -186,7 +318,7 @@
"name": "plus3", "name": "plus3",
"ligatures": "add card" "ligatures": "add card"
}, },
"setIdx": 8, "setIdx": 11,
"setId": 0, "setId": 0,
"iconIdx": 128 "iconIdx": 128
}, },
@ -212,7 +344,7 @@
"name": "arrow-left", "name": "arrow-left",
"ligatures": "back" "ligatures": "back"
}, },
"setIdx": 8, "setIdx": 11,
"setId": 0, "setId": 0,
"iconIdx": 205 "iconIdx": 205
}, },
@ -238,7 +370,7 @@
"name": "arrow-right", "name": "arrow-right",
"ligatures": "show detail" "ligatures": "show detail"
}, },
"setIdx": 8, "setIdx": 11,
"setId": 0, "setId": 0,
"iconIdx": 208 "iconIdx": 208
}, },
@ -268,7 +400,7 @@
"name": "security", "name": "security",
"ligatures": "lock" "ligatures": "lock"
}, },
"setIdx": 1, "setIdx": 4,
"setId": 9, "setId": 9,
"iconIdx": 293 "iconIdx": 293
}, },
@ -298,7 +430,7 @@
"name": "label", "name": "label",
"ligatures": "label" "ligatures": "label"
}, },
"setIdx": 1, "setIdx": 4,
"setId": 9, "setId": 9,
"iconIdx": 678 "iconIdx": 678
}, },
@ -325,7 +457,7 @@
"name": "gear", "name": "gear",
"ligatures": "options" "ligatures": "options"
}, },
"setIdx": 2, "setIdx": 5,
"setId": 8, "setId": 8,
"iconIdx": 64 "iconIdx": 64
}, },
@ -358,7 +490,7 @@
"ligatures": "other file", "ligatures": "other file",
"name": "file-empty" "name": "file-empty"
}, },
"setIdx": 3, "setIdx": 6,
"setId": 7, "setId": 7,
"iconIdx": 36 "iconIdx": 36
}, },
@ -392,7 +524,7 @@
"ligatures": "text file", "ligatures": "text file",
"name": "file-text2" "name": "file-text2"
}, },
"setIdx": 3, "setIdx": 6,
"setId": 7, "setId": 7,
"iconIdx": 38 "iconIdx": 38
}, },
@ -423,7 +555,7 @@
"ligatures": "image file", "ligatures": "image file",
"name": "file-picture" "name": "file-picture"
}, },
"setIdx": 3, "setIdx": 6,
"setId": 7, "setId": 7,
"iconIdx": 39 "iconIdx": 39
}, },
@ -454,7 +586,7 @@
"ligatures": "audio file", "ligatures": "audio file",
"name": "file-music" "name": "file-music"
}, },
"setIdx": 3, "setIdx": 6,
"setId": 7, "setId": 7,
"iconIdx": 40 "iconIdx": 40
}, },
@ -485,7 +617,7 @@
"ligatures": "video file", "ligatures": "video file",
"name": "file-video" "name": "file-video"
}, },
"setIdx": 3, "setIdx": 6,
"setId": 7, "setId": 7,
"iconIdx": 42 "iconIdx": 42
}, },
@ -525,7 +657,7 @@
"ligatures": "archive file", "ligatures": "archive file",
"name": "file-zip" "name": "file-zip"
}, },
"setIdx": 3, "setIdx": 6,
"setId": 7, "setId": 7,
"iconIdx": 43 "iconIdx": 43
}, },
@ -554,7 +686,7 @@
"ligatures": "password generator", "ligatures": "password generator",
"name": "key" "name": "key"
}, },
"setIdx": 3, "setIdx": 6,
"setId": 7, "setId": 7,
"iconIdx": 141 "iconIdx": 141
}, },
@ -583,7 +715,7 @@
"ligatures": "view password", "ligatures": "view password",
"name": "eye" "name": "eye"
}, },
"setIdx": 3, "setIdx": 6,
"setId": 7, "setId": 7,
"iconIdx": 206 "iconIdx": 206
}, },
@ -617,7 +749,7 @@
"ligatures": "generate password", "ligatures": "generate password",
"name": "loop2" "name": "loop2"
}, },
"setIdx": 3, "setIdx": 6,
"setId": 7, "setId": 7,
"iconIdx": 302 "iconIdx": 302
}, },
@ -643,10 +775,10 @@
"order": 32, "order": 32,
"prevSize": 32, "prevSize": 32,
"code": 59958, "code": 59958,
"ligatures": "set password", "ligatures": "set password, download",
"name": "arrow-down" "name": "arrow-down"
}, },
"setIdx": 3, "setIdx": 6,
"setId": 7, "setId": 7,
"iconIdx": 310 "iconIdx": 310
}, },
@ -675,7 +807,7 @@
"ligatures": "pdf file", "ligatures": "pdf file",
"name": "file-pdf" "name": "file-pdf"
}, },
"setIdx": 3, "setIdx": 6,
"setId": 7, "setId": 7,
"iconIdx": 474 "iconIdx": 474
}, },
@ -701,7 +833,7 @@
"name": "tag", "name": "tag",
"ligatures": "tag" "ligatures": "tag"
}, },
"setIdx": 4, "setIdx": 7,
"setId": 6, "setId": 6,
"iconIdx": 0 "iconIdx": 0
}, },
@ -728,7 +860,7 @@
"name": "tags", "name": "tags",
"ligatures": "tags" "ligatures": "tags"
}, },
"setIdx": 4, "setIdx": 7,
"setId": 6, "setId": 6,
"iconIdx": 1 "iconIdx": 1
}, },
@ -755,7 +887,7 @@
"name": "clock", "name": "clock",
"ligatures": "recent" "ligatures": "recent"
}, },
"setIdx": 4, "setIdx": 7,
"setId": 6, "setId": 6,
"iconIdx": 2 "iconIdx": 2
}, },
@ -784,7 +916,7 @@
"name": "spinner", "name": "spinner",
"ligatures": "loading" "ligatures": "loading"
}, },
"setIdx": 4, "setIdx": 7,
"setId": 6, "setId": 6,
"iconIdx": 3 "iconIdx": 3
}, },
@ -812,7 +944,7 @@
"name": "search", "name": "search",
"ligatures": "search" "ligatures": "search"
}, },
"setIdx": 4, "setIdx": 7,
"setId": 6, "setId": 6,
"iconIdx": 4 "iconIdx": 4
}, },
@ -840,7 +972,7 @@
"name": "locked", "name": "locked",
"ligatures": "locked" "ligatures": "locked"
}, },
"setIdx": 4, "setIdx": 7,
"setId": 6, "setId": 6,
"iconIdx": 6 "iconIdx": 6
}, },
@ -866,7 +998,7 @@
"name": "unlocked", "name": "unlocked",
"ligatures": "unlocked" "ligatures": "unlocked"
}, },
"setIdx": 4, "setIdx": 7,
"setId": 6, "setId": 6,
"iconIdx": 7 "iconIdx": 7
}, },
@ -895,7 +1027,7 @@
"name": "menu", "name": "menu",
"ligatures": "menu" "ligatures": "menu"
}, },
"setIdx": 4, "setIdx": 7,
"setId": 6, "setId": 6,
"iconIdx": 8 "iconIdx": 8
}, },
@ -924,7 +1056,7 @@
"name": "close", "name": "close",
"ligatures": "failure, failed, delete, clear, cancel, close" "ligatures": "failure, failed, delete, clear, cancel, close"
}, },
"setIdx": 4, "setIdx": 7,
"setId": 6, "setId": 6,
"iconIdx": 9 "iconIdx": 9
}, },
@ -953,61 +1085,9 @@
"name": "checkmark", "name": "checkmark",
"ligatures": "done, ok, save" "ligatures": "done, ok, save"
}, },
"setIdx": 4, "setIdx": 7,
"setId": 6, "setId": 6,
"iconIdx": 10 "iconIdx": 10
},
{
"icon": {
"paths": [
"M2.259 734.824h279.462v286.917h-279.462v-286.917z",
"M2.259 2.259h279.462v286.917h-279.462v-286.917z",
"M2.259 368.519h279.462v286.917h-279.462v-286.917z"
],
"width": 284,
"grid": 0,
"tags": [
"commands"
],
"attrs": []
},
"attrs": [],
"properties": {
"order": 18,
"id": 1,
"prevSize": 24,
"code": 58899,
"name": "commands",
"ligatures": "commands"
},
"setIdx": 5,
"setId": 4,
"iconIdx": 0
},
{
"icon": {
"paths": [
"M667.586 345.635v-338.544h-268.055v338.544l-299.967-121.263-90.486 257.986 310.037 104.527-198.134 262.808 224.514 164.237 184.802-279.685 203.382 279.685 221.11-164.237-203.382-262.808 319.397-107.080-90.486-257.986zM1220.574 2319.317z"
],
"width": 1080,
"grid": 0,
"tags": [
"logo"
],
"attrs": []
},
"attrs": [],
"properties": {
"order": 4,
"id": 0,
"prevSize": 24,
"code": 58884,
"name": "logo",
"ligatures": "clipperz"
},
"setIdx": 5,
"setId": 4,
"iconIdx": 1
} }
], ],
"height": 1024, "height": 1024,

File diff suppressed because one or more lines are too long

View File

@ -69,7 +69,7 @@ Clipperz.Base.extend(Clipperz.Async.Deferred, MochiKit.Async.Deferred, {
if (! (aResult instanceof MochiKit.Async.CancelledError)) { if (! (aResult instanceof MochiKit.Async.CancelledError)) {
message = "ERROR [" + deferredName + "]"; message = "ERROR [" + deferredName + "]";
} else { } else {
message = "CANCELLED - " + deferredName; message = "CANCELED - " + deferredName;
} }
Clipperz.log(message, aResult); Clipperz.log(message, aResult);

View File

@ -497,7 +497,7 @@ var state = new array(4);
var count = new array(2); var count = new array(2);
count[0] = 0; count[0] = 0;
count[1] = 0; count[1] = 0;
var buffer = new array(64); var md5_buffer = new array(64);
var transformBuffer = new array(16); var transformBuffer = new array(16);
var digestBits = new array(16); var digestBits = new array(16);
@ -683,9 +683,9 @@ function md5_update(b) {
count[0] -= 0xFFFFFFFF + 1; count[0] -= 0xFFFFFFFF + 1;
count[0] += 8; count[0] += 8;
} }
buffer[index] = and(b, 0xff); md5_buffer[index] = and(b, 0xff);
if (index >= 63) { if (index >= 63) {
transform(buffer, 0); transform(md5_buffer, 0);
} }
} }

View File

@ -497,9 +497,11 @@ Clipperz.PM.Connection.SRP['1.0'].prototype = MochiKit.Base.update(new Clipperz.
Clipperz.log(">>> Connection.messageExceptionHandler: " + anError.message, anError); Clipperz.log(">>> Connection.messageExceptionHandler: " + anError.message, anError);
if (anError instanceof MochiKit.Async.CancelledError) { if (anError instanceof MochiKit.Async.CancelledError) {
result = anError; result = anError;
} else if (typeof(anError.req) == 'undefined') {
result = anError;
} else { } else {
var errorPayload; var errorPayload;
errorPayload = Clipperz.Base.evalJSON(anError.req.responseText); errorPayload = Clipperz.Base.evalJSON(anError.req.responseText);
if ((errorPayload.message == 'Trying to communicate without an active connection') || if ((errorPayload.message == 'Trying to communicate without an active connection') ||
(errorPayload.message == 'No tollManager available for current session') || (errorPayload.message == 'No tollManager available for current session') ||

View File

@ -104,18 +104,23 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Attachment, Object, {
}, },
'setFile': function (aFile) { 'setFile': function (aFile) {
var hashValue;
//console.log("ATTACHMENT SET FILE", aFile);
this._file = aFile || null; this._file = aFile || null;
// hashValue = aFile ? npm.bitcoin.address.toBase58Check(npm.bitcoin.crypto.hash160(aFile), NETWORK.pubKeyHash) : null;
/* These ones will disappear when the application is closed */ /* These ones will disappear when the application is closed */
this._name = aFile ? aFile['name'] : null; this._name = aFile ? aFile['name'] : null;
this._contentType = aFile ? aFile['type'] : null; this._contentType = aFile ? aFile['type'] : null;
this._size = aFile ? aFile['size'] : null; this._size = aFile ? aFile['size'] : null;
// this._hash = hashValue;
/* These ones will be saved in the Record */ /* These ones will be saved in the Record */
return Clipperz.Async.callbacks("Attachment.setFile", [ return Clipperz.Async.callbacks("Attachment.setFile", [
MochiKit.Base.method(this, 'setValue', 'name', aFile['name']), MochiKit.Base.method(this, 'setValue', 'name', aFile['name']),
MochiKit.Base.method(this, 'setValue', 'contentType', aFile['type']), MochiKit.Base.method(this, 'setValue', 'contentType', aFile['type']),
MochiKit.Base.method(this, 'setValue', 'size', aFile['size']), MochiKit.Base.method(this, 'setValue', 'size', aFile['size']),
// MochiKit.Base.method(this, 'setValue', 'hash', hashValue),
MochiKit.Base.partial(MochiKit.Async.succeed, this), MochiKit.Base.partial(MochiKit.Async.succeed, this),
], {trace:false}); ], {trace:false});
@ -135,6 +140,10 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Attachment, Object, {
return this.getValue('size'); return this.getValue('size');
}, },
'hash': function () {
return this.getValue('hash');
},
'metadata': function () { 'metadata': function () {
var deferredResult; var deferredResult;
@ -143,6 +152,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Attachment, Object, {
'name': MochiKit.Base.method(this, 'name'), 'name': MochiKit.Base.method(this, 'name'),
'type': MochiKit.Base.method(this, 'contentType'), 'type': MochiKit.Base.method(this, 'contentType'),
'size': MochiKit.Base.method(this, 'size'), 'size': MochiKit.Base.method(this, 'size'),
'hash': MochiKit.Base.method(this, 'hash'),
}, {trace:false}); }, {trace:false});
deferredResult.callback(); deferredResult.callback();
@ -346,6 +356,30 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Attachment, Object, {
}, },
//========================================================================= //=========================================================================
/*
computeAttachmentCertificateInfo: function () {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("Attachment.computeAttachmentCertificateInfo", {trace:false});
deferredResult.collectResults({
'name': MochiKit.Base.method(this, 'name'),
'contentType': MochiKit.Base.method(this, 'contentType'),
'size': MochiKit.Base.method(this, 'size'),
'hash': [
MochiKit.Base.method(attachmentController, 'getAttachment', this),
function (aValue) { console.log("STEP 1", aValue); return aValue; },
// npm.bitcoin.crypto.hash160,
//function (aValue) { console.log("STEP 2", aValue); return aValue; },
// function (anHash160) { return npm.bitcoin.address.toBase58Check(anHash160, NETWORK.pubKeyHash);}
function () { return MochiKit.Async.succeed("bingo"); }
]
});
deferredResult.callback();
return deferredResult;
},
*/
//=========================================================================
__syntaxFix__: "syntax fix" __syntaxFix__: "syntax fix"
}); });

View File

@ -69,16 +69,17 @@ Clipperz.PM.DataModel.EncryptedRemoteObject = function(args) {
// //
// Basic data workflow // Basic data workflow
// ======================= // =======================
// // # READ
// getRemoteData // getRemoteData
// unpackRemoteData // unpackRemoteData
// getDecryptedData [encryptedDataKeypath, encryptedVersionKeypath] // getDecryptedData [encryptedDataKeypath, encryptedVersionKeypath]
// unpackData // unpackData
// //
// // # WRITE
// ?? packData // prepareRemoteDataWithKey
// ?? encryptDataWithKey // packData
// ?? packRemoteData [encryptedDataKeypath (?), encryptedVersionKeypath (?)] // [encryptDataWithKey]
// packRemoteData [encryptedDataKeypath (?), encryptedVersionKeypath (?)]
// //
Clipperz.PM.DataModel.EncryptedRemoteObject.prototype = MochiKit.Base.update(null, { Clipperz.PM.DataModel.EncryptedRemoteObject.prototype = MochiKit.Base.update(null, {
@ -284,7 +285,18 @@ Clipperz.PM.DataModel.EncryptedRemoteObject.prototype = MochiKit.Base.update(nul
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
'setValue': function(aKey, aValue) { 'getOrSetValue': function (aKey, aGetValueFunction) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.setValue", {trace:false});
deferredResult.addMethod(this, '_getObjectDataStore');
deferredResult.addCallback(MochiKit.Base.methodcaller('deferredGetOrSet', aKey, aGetValueFunction));
deferredResult.callback();
return deferredResult;
},
'setValue': function (aKey, aValue) {
var deferredResult; var deferredResult;
deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.setValue", {trace:false}); deferredResult = new Clipperz.Async.Deferred("EncryptedRemoteObject.setValue", {trace:false});

View File

@ -183,7 +183,7 @@ Clipperz.PM.DataModel.OneTimePassword.isValidOneTimePasswordValue = function(aPa
var result; var result;
// "yaxx k7ww - f8y6 tqz5 - 58b6 th44 - 9cwv q0fg" // "yaxx k7ww - f8y6 tqz5 - 58b6 th44 - 9cwv q0fg"
if (aPassword.replace(/[\s\-]/g, '').length == 32) { if (aPassword.replace(/[^a-zA-Z0-9]/g, '').length == 32) {
try { try {
var passwordByteArray; var passwordByteArray;

View File

@ -49,6 +49,7 @@ Clipperz.PM.DataModel.Record = function(args) {
this._createNewAttachmentFunction = args.createNewAttachmentFunction || null; this._createNewAttachmentFunction = args.createNewAttachmentFunction || null;
this._attachmentServerStatus = {}; this._attachmentServerStatus = {};
this._certificateInfo = null;
this._tags = []; this._tags = [];
this._directLogins = {}; this._directLogins = {};
@ -63,7 +64,6 @@ Clipperz.PM.DataModel.Record = function(args) {
newVersion = new Clipperz.PM.DataModel.Record.Version({ newVersion = new Clipperz.PM.DataModel.Record.Version({
'retrieveKeyFunction': MochiKit.Base.method(this, 'getVersionKey'), 'retrieveKeyFunction': MochiKit.Base.method(this, 'getVersionKey'),
'getVersion': MochiKit.Base.method(this, 'getVersion') 'getVersion': MochiKit.Base.method(this, 'getVersion')
}); });
this._versions[newVersion.reference()] = newVersion; this._versions[newVersion.reference()] = newVersion;
this._currentVersionReference = newVersion.reference(); this._currentVersionReference = newVersion.reference();
@ -85,7 +85,288 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
// 'reference': function () { // 'reference': function () {
// return this._reference; // return this._reference;
// }, // },
//=========================================================================
setID: function (anID) {
//console.log("RECORD - SET ID", this, anID);
return this.setValue('ID', anID);
},
getID: function () {
return this.getValue('ID');
},
//=========================================================================
collectFieldInfo: function (aField) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('Record.collectFieldInfo', {trace:false});
deferredResult.setValue('_field');
deferredResult.addMethod(aField, 'reference');
deferredResult.setValue('_reference');
deferredResult.addMethod(aField, 'label');
deferredResult.setValue('label');
deferredResult.addMethod(aField, 'value');
deferredResult.setValue('value');
deferredResult.addMethod(aField, 'actionType');
deferredResult.setValue('actionType');
deferredResult.addMethod(aField, 'isHidden');
deferredResult.setValue('isHidden');
deferredResult.values();
deferredResult.callback(aField);
return deferredResult;
},
collectDirectLoginInfo: function (aDirectLogin) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('Record.collectDirectLoginInfo', {trace:false});
deferredResult.addMethod(aDirectLogin, 'reference');
deferredResult.setValue('_reference');
deferredResult.addMethod(aDirectLogin, 'label');
deferredResult.setValue('label');
deferredResult.addMethod(aDirectLogin, 'favicon');
deferredResult.setValue('favicon');
deferredResult.values();
deferredResult.callback();
return deferredResult;
},
collectAttachmentInfo: function(anAttachment) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('Record.collectAttachmentInfo', {trace:false});
deferredResult.setValue('_attachment'); // The object itself, maybe this should be the only value being passed
deferredResult.addMethod(anAttachment, 'reference');
deferredResult.setValue('_reference');
deferredResult.addMethod(anAttachment, 'name');
deferredResult.setValue('name');
deferredResult.addMethod(anAttachment, 'contentType');
deferredResult.setValue('contentType');
deferredResult.addMethod(anAttachment, 'size');
deferredResult.setValue('size');
deferredResult.addMethod(anAttachment, 'hash');
deferredResult.setValue('hash');
deferredResult.values();
deferredResult.callback(anAttachment);
return deferredResult;
},
collectRecordInfo: function () {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('Record.collectRecordInfo', {trace:false});
deferredResult.setValue('_record');
deferredResult.addMethod(this, 'reference');
deferredResult.setValue('_reference');
deferredResult.addMethod(this, 'isArchived');
deferredResult.setValue('_isArchived');
deferredResult.addMethod(this, 'isBrandNew');
deferredResult.setValue('_isBrandNew');
deferredResult.addMethod(this, 'label');
deferredResult.setValue('label');
deferredResult.addMethod(this, 'notes');
deferredResult.setValue('notes');
deferredResult.addMethod(this, 'tags');
deferredResult.setValue('tags');
deferredResult.addMethod(this, 'getID');
deferredResult.setValue('ID');
deferredResult.addMethod(this, 'fields');
deferredResult.addCallback(MochiKit.Base.values);
deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'collectFieldInfo'));
deferredResult.addCallback(Clipperz.Async.collectAll);
deferredResult.setValue('fields');
deferredResult.addMethod(this, 'certificateInfo');
deferredResult.addCallback(MochiKit.Base.bind(function (someCertificateInfo) {
var result;
if ((someCertificateInfo) && (someCertificateInfo['status'] == 'requested')) {
result = this.updateCertificateInfo()
} else {
result = MochiKit.Async.succeed(someCertificateInfo);
}
return result;
}, this));
deferredResult.setValue('certificateInfo');
deferredResult.addMethod(this, 'attachmentsInfo');
deferredResult.setValue('attachments');
deferredResult.addMethod(this, 'directLogins');
deferredResult.addCallback(MochiKit.Base.values);
deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'collectDirectLoginInfo'));
deferredResult.addCallback(Clipperz.Async.collectAll);
deferredResult.setValue('directLogins');
deferredResult.addMethod(this, 'getAttachmentServerStatus');
deferredResult.setValue('attachmentServerStatus');
deferredResult.values();
deferredResult.callback(this);
return deferredResult;
},
//=========================================================================
certificateMetadata: function () {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred('Record.certificateMetadata', {trace:false});
deferredResult.addMethod(this, 'collectRecordInfo');
deferredResult.addCallback(function (someValues) {
var result = {};
var propertiesToCollect = ['label', 'notes'];
var fieldPropertiesToCollect = ['label', 'value'];
var attachmentPropertiesToCollect = ['name', 'contentType', 'size', 'hash'];
MochiKit.Iter.forEach(propertiesToCollect, function (aKey) { result[aKey] = someValues[aKey]});
result['fields'] = MochiKit.Base.map(function (aField) {
var fieldResult = {};
MochiKit.Iter.forEach(fieldPropertiesToCollect, function (aKey) { fieldResult[aKey] = aField[aKey]});
return fieldResult;
}, someValues['fields']);
result['attachments'] = MochiKit.Base.map(function (anAttachment) {
var attachmentResult = {};
MochiKit.Iter.forEach(attachmentPropertiesToCollect, function (aKey) { attachmentResult[aKey] = anAttachment[aKey]});
return attachmentResult;
}, someValues['attachments']);
if (result['notes'] == "") {
delete result['notes'];
}
return result;
});
deferredResult.addCallback(Clipperz.Base.serializeJSON);
//deferredResult.addCallback(function (aValue) { console.log("<<< CERTIFICATE METADATA", aValue); return aValue;});
deferredResult.callback();
return deferredResult;
},
//=========================================================================
/*
publicKeyBufferFromHash256: function (aBuffer) {
// var fixedBuffer;
//
// fixedBuffer = new npm.buffer.Buffer(33);
// fixedBuffer.writeUInt8(0x03, 0); // https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki
// aBuffer.copy(fixedBuffer, 1);
//
// return npm.bitcoin.ECPair.fromPublicKeyBuffer(fixedBuffer, NETWORK);
return npm.bitcoin.HDNode.fromSeedHex(aBuffer.toString('hex')).getPublicKeyBuffer();
},
*/
keyFromHash256: function (aBuffer) {
// return npm.bitcoin.HDNode.fromSeedHex(aBuffer.toString('hex'), NETWORK);
var d = npm.BigInteger.fromHex(aBuffer.toString('hex'));
return new npm.bitcoin.ECPair(d, null, {'network':NETWORK, 'compressed':true})
},
computeAttachmentsCertificateInfo: function (attachmentController) {
var deferredResult;
var collectResultsInfo = {};
var shouldComputeResult = false;
var self = this;
MochiKit.Iter.forEach(MochiKit.Base.values(this.attachments()), function (anAttachment) {
shouldComputeResult = true;
collectResultsInfo[anAttachment.reference()] = [
MochiKit.Base.method(anAttachment, 'metadata'),
MochiKit.Base.itemgetter('hash'),
function (anHashValue) {
var hashBuffer = new npm.buffer.Buffer(anHashValue, 'hex');
var key = self.keyFromHash256(hashBuffer);
return {
'hash': anHashValue,
'publicKey': key.getPublicKeyBuffer().toString('hex'),
'address': key.getAddress(),
}
}
];
});
if (shouldComputeResult) {
deferredResult = new Clipperz.Async.Deferred("Record.computeAttachmentsCertificateInfo", {trace:false});
deferredResult.collectResults(collectResultsInfo);
deferredResult.callback();
} else {
deferredResult = MochiKit.Async.succeed(collectResultsInfo);
}
return deferredResult;
},
computeCertificateInfo: function (aWallet) {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("Record.computeCertificateInfo", {trace:false});
deferredResult.collectResults({
'reference': MochiKit.Base.method(this, 'reference'),
'version': MochiKit.Base.partial(MochiKit.Async.succeed, "1.0"),
'card.publicKey': [
MochiKit.Base.method(this, 'getID'),
MochiKit.Base.method(aWallet, 'getKeyForDocumentWithID'),
MochiKit.Base.methodcaller('getPublicKeyBuffer'),
MochiKit.Base.methodcaller('toString', 'hex'),
],
'card.address': [
MochiKit.Base.method(this, 'getID'),
MochiKit.Base.method(aWallet, 'getKeyForDocumentWithID'),
MochiKit.Base.methodcaller('getAddress')
],
/*
'metadata': [
MochiKit.Base.method(this, 'certificateMetadata'),
function (aString) { return new npm.buffer.Buffer(aString, 'utf8') },
npm.bitcoin.crypto.hash160,
function (anHash160) { return npm.bitcoin.address.toBase58Check(anHash160, NETWORK.pubKeyHash);}
],
*/
'metadata.publicKey': [
MochiKit.Base.method(this, 'certificateMetadata'),
function (aString) { return new npm.buffer.Buffer(aString, 'utf8') },
npm.bitcoin.crypto.hash256,
MochiKit.Base.method(this, 'keyFromHash256'),
MochiKit.Base.methodcaller('getPublicKeyBuffer'),
MochiKit.Base.methodcaller('toString', 'hex'),
],
'metadata.address': [
MochiKit.Base.method(this, 'certificateMetadata'),
function (aString) { return new npm.buffer.Buffer(aString, 'utf8') },
npm.bitcoin.crypto.hash256,
MochiKit.Base.method(this, 'keyFromHash256'),
MochiKit.Base.methodcaller('getAddress')
],
'attachments': MochiKit.Base.method(this, 'computeAttachmentsCertificateInfo')
});
//deferredResult.addCallback(function (aValue) { console.log("=== CERTIFICATE INFO", MochiKit.Base.serializeJSON(aValue)); return aValue;});
deferredResult.callback();
return deferredResult;
},
//========================================================================= //=========================================================================
'getIndexData': function () { 'getIndexData': function () {
@ -149,6 +430,33 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
return this._attachmentServerStatus; return this._attachmentServerStatus;
}, },
updatedAttachmentServerStatus: function () {
return Clipperz.Async.callbacks("Record.updatedAttachmentServerStatus", [
MochiKit.Base.partial(this.retrieveRemoteDataFunction(), this),
MochiKit.Base.itemgetter('attachmentStatus'),
MochiKit.Base.method(this, 'setAttachmentServerStatus'),
], {trace:false});
},
//----------------------------------------------------------------------------
setCertificateInfo: function (aValue) {
this._certificateInfo = aValue;
return this._certificateInfo;
},
certificateInfo: function () {
return this._certificateInfo;
},
updateCertificateInfo: function () {
return Clipperz.Async.callbacks("Record.updateCertificateInfo", [
MochiKit.Base.partial(this.retrieveRemoteDataFunction(), this),
MochiKit.Base.itemgetter('certificateInfo'),
MochiKit.Base.method(this, 'setCertificateInfo'),
], {trace:false});
},
//============================================================================ //============================================================================
/* /*
'key': function () { 'key': function () {
@ -302,8 +610,32 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
//========================================================================= //=========================================================================
attachmentsCount: function() { certificateStatus: function() {
return MochiKit.Base.keys(this.attachments()).length; // TODO: FAKE IMPLEMENTATION, just enough to test the UI
var result;
// if (this.reference().charAt(0) == 'a') {
// result = 'published';
// } else if (this.reference().charAt(0) == '0') {
// result = 'requested';
// } else {
// result = '';
// }
result = '';
return result; // 'requested' | 'published' | ''
},
markAsCertified: function () {
return this.addTag(Clipperz.PM.DataModel.Record.certifiedTag);
},
hasBeenCertified: function () {
return Clipperz.Async.callbacks("Record.isArchived", [
MochiKit.Base.method(this, 'tags'),
function (someTags) { return MochiKit.Iter.some(someTags, MochiKit.Base.partial(MochiKit.Base.objEqual, Clipperz.PM.DataModel.Record.certifiedTag))},
], {trace:false});
}, },
//========================================================================= //=========================================================================
@ -486,6 +818,26 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
//========================================================================= //=========================================================================
// TODO: !!!! // TODO: !!!!
'attachmentsCount': function() {
return MochiKit.Base.keys(this.attachments()).length;
},
'attachmentsInfo': function () {
// deferredResult.addMethod(this, 'attachments');
// deferredResult.addCallback(MochiKit.Base.values);
// deferredResult.addCallback(MochiKit.Base.map, MochiKit.Base.method(this, 'collectAttachmentInfo'));
// deferredResult.addCallback(Clipperz.Async.collectAll);
return Clipperz.Async.callbacks("Record.attachmentsInfo", [
MochiKit.Base.method(this, 'attachments'),
MochiKit.Base.values,
MochiKit.Base.partial(MochiKit.Base.map, MochiKit.Base.method(this, 'collectAttachmentInfo')),
Clipperz.Async.collectAll
], {trace:false});
},
'attachments': function () { 'attachments': function () {
return this._attachments; return this._attachments;
}, },
@ -527,7 +879,6 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
delete this._attachments[anAttachment.reference()] delete this._attachments[anAttachment.reference()]
}, this) }, this)
], {trace:false}); ], {trace:false});
}, },
'attachmentReferences': function () { 'attachmentReferences': function () {
@ -563,16 +914,11 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
'unpackRemoteData': function (someData) { 'unpackRemoteData': function (someData) {
var result; var result;
/*
this._currentRecordVersion = new Clipperz.PM.DataModel.Record.Version({
'reference': someData['currentVersion']['reference'],
'retrieveKeyFunction': MochiKit.Base.method(this, 'getCurrentRecordVersionKey'),
'remoteData': someData['currentVersion'],
});
*/
var versionKey; var versionKey;
this.setAttachmentServerStatus(someData['attachmentStatus']);
this.setCertificateInfo(someData['certificateInfo']);
for (versionKey in someData['versions']) { for (versionKey in someData['versions']) {
this._versions[versionKey] = new Clipperz.PM.DataModel.Record.Version({ this._versions[versionKey] = new Clipperz.PM.DataModel.Record.Version({
'reference': versionKey, 'reference': versionKey,
@ -581,8 +927,6 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
'getVersion': MochiKit.Base.method(this, 'getVersion') 'getVersion': MochiKit.Base.method(this, 'getVersion')
}) })
} }
// this._currentVersionReference = someData['currentVersion']['reference'];
this._currentVersionReference = someData['currentVersion']; this._currentVersionReference = someData['currentVersion'];
result = Clipperz.PM.DataModel.Record.superclass.unpackRemoteData.apply(this, arguments); result = Clipperz.PM.DataModel.Record.superclass.unpackRemoteData.apply(this, arguments);
@ -596,11 +940,10 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.Record, Clipperz.PM.DataModel.Encrypt
var result; var result;
result = Clipperz.PM.DataModel.Record.superclass.unpackData.apply(this, arguments); result = Clipperz.PM.DataModel.Record.superclass.unpackData.apply(this, arguments);
if (MochiKit.Base.isUndefinedOrNull(result['notes'])) { if (MochiKit.Base.isUndefinedOrNull(result['notes'])) {
result['notes'] = '' result['notes'] = ''
} }
return result; return result;
}, },
@ -1218,6 +1561,12 @@ Clipperz.log("Warning: Record.fieldWithLabel('" + aLabel + "') is returning more
MochiKit.Base.method(aRecord, 'fullLabel'), MochiKit.Base.method(aRecord, 'fullLabel'),
MochiKit.Base.method(aRecord, 'extractTagsFromFullLabel'), MochiKit.Base.method(aRecord, 'extractTagsFromFullLabel'),
//function (someValues) { console.log(">>> TAGS", someValues); return someValues; },
MochiKit.Base.keys,
MochiKit.Base.partial(MochiKit.Base.filter, Clipperz.PM.DataModel.Record.isRegularTag),
MochiKit.Base.partial(MochiKit.Base.filter, Clipperz.PM.DataModel.Record.isNotImportTag),
function (tags) { return MochiKit.Iter.reduce(function (result, value) { result[value] = true; return result; }, tags, {}); },
//function (someValues) { console.log("<<< TAGS", someValues); return someValues; },
MochiKit.Base.method(this, 'updateTags'), MochiKit.Base.method(this, 'updateTags'),
MochiKit.Base.method(aRecord, 'notes'), MochiKit.Base.method(aRecord, 'notes'),
@ -1333,6 +1682,7 @@ Clipperz.PM.DataModel.Record.defaultCardInfo = {
'label': MochiKit.Base.methodcaller('label'), 'label': MochiKit.Base.methodcaller('label'),
'favicon': MochiKit.Base.methodcaller('favicon'), 'favicon': MochiKit.Base.methodcaller('favicon'),
'attachmentsCount': MochiKit.Base.methodcaller('attachmentsCount'), 'attachmentsCount': MochiKit.Base.methodcaller('attachmentsCount'),
'hasBeenCertified': MochiKit.Base.methodcaller('hasBeenCertified'),
}; };
Clipperz.PM.DataModel.Record.defaultSearchField = '_searchableContent'; Clipperz.PM.DataModel.Record.defaultSearchField = '_searchableContent';
@ -1342,7 +1692,9 @@ Clipperz.PM.DataModel.Record.specialTagChar = '\uE010';
Clipperz.PM.DataModel.Record.specialTagsConstructor = function (aTag) { Clipperz.PM.DataModel.Record.specialTagsConstructor = function (aTag) {
return Clipperz.PM.DataModel.Record.specialTagChar + aTag; //.replace(/\s/g, Clipperz.PM.DataModel.Record.tagSpace); return Clipperz.PM.DataModel.Record.specialTagChar + aTag; //.replace(/\s/g, Clipperz.PM.DataModel.Record.tagSpace);
} }
Clipperz.PM.DataModel.Record.archivedTag = Clipperz.PM.DataModel.Record.specialTagsConstructor('ARCH'); Clipperz.PM.DataModel.Record.archivedTag = Clipperz.PM.DataModel.Record.specialTagsConstructor('ARCH');
Clipperz.PM.DataModel.Record.certifiedTag = Clipperz.PM.DataModel.Record.specialTagsConstructor('CERT');
Clipperz.PM.DataModel.Record.regExpForTag = function (aTag) { Clipperz.PM.DataModel.Record.regExpForTag = function (aTag) {
return new RegExp('\\' + Clipperz.PM.DataModel.Record.tagChar + aTag, 'g'); return new RegExp('\\' + Clipperz.PM.DataModel.Record.tagChar + aTag, 'g');
}; };
@ -1355,6 +1707,9 @@ Clipperz.PM.DataModel.Record.isSpecialTag = function (aTag) {
Clipperz.PM.DataModel.Record.isRegularTag = function (aTag) { Clipperz.PM.DataModel.Record.isRegularTag = function (aTag) {
return !Clipperz.PM.DataModel.Record.isSpecialTag(aTag); return !Clipperz.PM.DataModel.Record.isSpecialTag(aTag);
}; };
Clipperz.PM.DataModel.Record.isNotImportTag = function (aTag) {
return aTag.indexOf('Import_') != 0;
};
Clipperz.PM.DataModel.Record.regExpForSearch = function (aSearch) { Clipperz.PM.DataModel.Record.regExpForSearch = function (aSearch) {
return new RegExp(aSearch.replace(/[^A-Za-z0-9]/g, '\\$&'), 'i'); return new RegExp(aSearch.replace(/[^A-Za-z0-9]/g, '\\$&'), 'i');
}; };

View File

@ -456,27 +456,15 @@ Clipperz.log("SKIPPING record " + reference + " as there are no stats associated
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
'createNewAttachment': function (aRecord) { 'createNewAttachment': function (aRecord) {
// TODO:
// var newDirectLogin;
var newAttachment; var newAttachment;
// var newDirectLoginIndexValue;
var newAttachmentIndexValue; var newAttachmentIndexValue;
// newDirectLogin = new Clipperz.PM.DataModel.DirectLogin({record:aRecord});
newAttachment = new Clipperz.PM.DataModel.Attachment({'record':aRecord}); newAttachment = new Clipperz.PM.DataModel.Attachment({'record':aRecord});
// newDirectLoginIndexValue = MochiKit.Base.listMax(MochiKit.Base.map(function (aValue) { return aValue * 1; }, MochiKit.Base.values(this.directLoginsIndex()))) + 1;
newAttachmentIndexValue = MochiKit.Base.listMax(MochiKit.Base.map(function (aValue) { return aValue * 1; }, MochiKit.Base.values(this.attachmentsIndex()))) + 1; newAttachmentIndexValue = MochiKit.Base.listMax(MochiKit.Base.map(function (aValue) { return aValue * 1; }, MochiKit.Base.values(this.attachmentsIndex()))) + 1;
// this.transientState().setValue('newDirectLoginReferences' + '.' + newDirectLogin.reference(), newDirectLogin);
this.transientState().setValue('newAttachmentReferences' + '.' + newAttachment.reference(), newAttachment); this.transientState().setValue('newAttachmentReferences' + '.' + newAttachment.reference(), newAttachment);
// this.directLoginsIndex()[newDirectLogin.reference()] = newDirectLoginIndexValue;
this.attachmentsIndex()[newAttachment.reference()] = newAttachmentIndexValue; this.attachmentsIndex()[newAttachment.reference()] = newAttachmentIndexValue;
// this.directLoginsData().setValue(this.directLoginsIndex()[newDirectLogin.reference()], {'record': this.recordsIndex()[aRecord.reference()]});
this.attachmentsData().setValue(this.attachmentsIndex()[newAttachment.reference()], {'record': this.recordsIndex()[aRecord.reference()]}); this.attachmentsData().setValue(this.attachmentsIndex()[newAttachment.reference()], {'record': this.recordsIndex()[aRecord.reference()]});
// return newDirectLogin;
return newAttachment; return newAttachment;
}, },

View File

@ -0,0 +1,174 @@
/*
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/.
*/
try { if (typeof(Clipperz.PM.DataModel.User) == 'undefined') { throw ""; }} catch (e) {
throw "Clipperz.PM.DataModel.User.Header.Wallet depends on Clipperz.PM.DataModel.User!";
}
if (typeof(Clipperz.PM.DataModel.User.Header) == 'undefined') { Clipperz.PM.DataModel.User.Header = {}; }
Clipperz.PM.DataModel.User.Header.Wallet = function(args) {
Clipperz.PM.DataModel.User.Header.Wallet.superclass.constructor.apply(this, arguments);
return this;
}
Clipperz.Base.extend(Clipperz.PM.DataModel.User.Header.Wallet, Clipperz.PM.DataModel.EncryptedRemoteObject, {
'toString': function() {
return "Clipperz.PM.DataModel.User.Header.Wallet";
},
//-------------------------------------------------------------------------
getRandomSeed: function () {
return Clipperz.Crypto.PRNG.defaultRandomGenerator().getRandomBytes(512/8).toHexString().substring(2);
},
getWalletSeed: function () {
return this.getOrSetValue('walletSeed', MochiKit.Base.method(this, 'getRandomSeed'));
},
userMasterKey: function () {
return Clipperz.Async.callbacks("User.Header.Wallet.userMasterKey", [
MochiKit.Base.method(this, 'getWalletSeed'),
function (aValue) {
return npm.bitcoin.HDNode.fromSeedHex(aValue, NETWORK);
}
], {trace:false});
},
getNextID: function (aKeyPath) {
//console.log("WALLET - getNextID", aKeyPath);
return Clipperz.Async.callbacks("User.Header.Wallet.userMasterKey", [
MochiKit.Base.method(this, 'getValue', aKeyPath),
function (aValue) {
var result;
if (aValue == null) {
result = 0;
} else {
result = aValue + 1;
}
return result;
},
MochiKit.Base.method(this, 'setValue', aKeyPath)
], {trace:false});
},
getKeyForDocumentWithID: function (anID) {
return Clipperz.Async.callbacks("User.Header.Wallet.getKeyForDocumentWithID", [
MochiKit.Base.method(this, 'userMasterKey'),
MochiKit.Base.methodcaller('derive', 0),
MochiKit.Base.methodcaller('derive', anID)
], {trace:false});
},
// getPublicKeyForDocumentWithID: function (anID) {
// return Clipperz.Async.callbacks("User.Header.Wallet.getPublicKeyForDocumentWithID", [
// MochiKit.Base.method(this, 'getKeyForDocumentWithID', anID),
// MochiKit.Base.methodcaller('getPublicKeyBuffer'),
// MochiKit.Base.methodcaller('toString', 'hex'),
// ], {trace:false});
// },
// getAddressForDocumentWithID: function (anID) {
//console.log("WALLET - address for document with ID", anID);
// return Clipperz.Async.callbacks("User.Header.Wallet.getAddressForDocumentWithID", [
// MochiKit.Base.method(this, 'getKeyForDocumentWithID', anID),
// MochiKit.Base.methodcaller('getAddress')
// ], {trace:false});
// },
//#########################################################################
// prepareRemoteDataWithKey
// packData
// encryptDataWithKey
// packRemoteData [encryptedDataKeypath (?), encryptedVersionKeypath (?)]
/*
prepareRemoteDataWithKey: function (aKey) {
console.log("USER HEADER WALLET - prepareRemoteDataWithKey", aKey);
//console.log("super", Clipperz.PM.DataModel.User.Header.Wallet.superclass.prepareRemoteDataWithKey);
return Clipperz.PM.DataModel.User.Header.Wallet.superclass.prepareRemoteDataWithKey.apply(this, arguments);
},
packData: function (someData) { // ++
console.log("USER HEADER WALLET - packData", someData);
return Clipperz.PM.DataModel.User.Header.Wallet.superclass.packData.apply(this, arguments);
},
packRemoteData: function (someData) {
console.log("USER HEADER WALLET - packRemoteData", someData);
return Clipperz.PM.DataModel.User.Header.Wallet.superclass.packRemoteData.apply(this, arguments);
},
*/
//#########################################################################
/*
'mergePreferences': function(somePreferences, someOtherPreferences) {
var result;
result = new Clipperz.KeyValueObjectStore();
result.setValues(MochiKit.Base.updatetree(
Clipperz.Base.deepClone(someOtherPreferences),
somePreferences
));
return result;
},
'mergeDefaultPreferences': function(somePreferences) {
return this.mergePreferences(somePreferences, Clipperz.PM.DataModel.User.Header.Preferences.defaultPreferences);
},
'mergeUserPreferences': function(somePreferences) {
return this.mergePreferences(somePreferences, this._objectDataStore.values());
},
'getPreferences': function() {
return Clipperz.Async.callbacks("User.Header.Preferences.getPreferences", [
MochiKit.Base.method(this, 'values'),
MochiKit.Base.method(this, 'mergeDefaultPreferences')
], {trace:false});
},
'getPreference': function(aKey) {
return Clipperz.Async.callbacks("User.Header.Preferences.getPreference", [
MochiKit.Base.method(this, 'getPreferences'),
MochiKit.Base.methodcaller('getValue', aKey)
], {trace:false});
},
'setPreferences': function(anObject) {
return Clipperz.Async.callbacks("User.Header.Preferences.setPreferences", [
MochiKit.Base.method(this, 'mergeUserPreferences', anObject),
MochiKit.Base.methodcaller('values'),
MochiKit.Base.method(this, 'setValues')
], {trace:false});
},
*/
//=========================================================================
__syntaxFix__: "syntax fix"
});

View File

@ -52,10 +52,6 @@ Clipperz.PM.DataModel.User = function (args) {
this._deferredLocks = { this._deferredLocks = {
'passphrase': new MochiKit.Async.DeferredLock(), 'passphrase': new MochiKit.Async.DeferredLock(),
'serverData': new MochiKit.Async.DeferredLock(), 'serverData': new MochiKit.Async.DeferredLock(),
// 'recordsIndex': new MochiKit.Async.DeferredLock(),
// 'directLoginsIndex': new MochiKit.Async.DeferredLock()
// 'preferences': new MochiKit.Async.DeferredLock()
// 'oneTimePasswords': new MochiKit.Async.DeferredLock()
'__syntaxFix__': 'syntax fix' '__syntaxFix__': 'syntax fix'
}; };
@ -267,6 +263,10 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
'name': 'oneTimePasswords', 'name': 'oneTimePasswords',
'username': this.username(), 'username': this.username(),
'passphraseCallback': MochiKit.Base.method(this, 'getPassphrase') 'passphraseCallback': MochiKit.Base.method(this, 'getPassphrase')
}),
'wallet': new Clipperz.PM.DataModel.User.Header.Wallet({
'name': 'wallet',
'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
}) })
} }
}; };
@ -391,6 +391,24 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
this.setAccountInfo(new Clipperz.PM.DataModel.User.AccountInfo(aValue['accountInfo'])); this.setAccountInfo(new Clipperz.PM.DataModel.User.AccountInfo(aValue['accountInfo']));
}, },
'updateAccountInfo': function () {
var deferredResult;
deferredResult = new Clipperz.Async.Deferred("User.updateAccountInfo", {trace:false});
deferredResult.addMethod(this.connection(), 'message', 'accountInfo');
// deferredResult.addCallback(function (aValue) {
//console.log("ACCOUNT INFO", aValue);
// return new Clipperz.PM.DataModel.User.AccountInfo(aValue);
// })
deferredResult.addMethod(this, 'setupAccountInfo');
deferredResult.addErrback (MochiKit.Base.method(this, 'handleConnectionFallback'));
deferredResult.callback();
return deferredResult;
},
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
'lock': function () { 'lock': function () {
@ -439,8 +457,9 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
var headerVersion; var headerVersion;
var recordsIndex; var recordsIndex;
var preferences; var preferences;
var oneTimePasswords; var oneTimePasswords;
var wallet;
headerVersion = this.headerFormatVersion(someServerData['header']); headerVersion = this.headerFormatVersion(someServerData['header']);
switch (headerVersion) { switch (headerVersion) {
@ -462,6 +481,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
recordsIndex = legacyHeader; recordsIndex = legacyHeader;
preferences = legacyHeader; preferences = legacyHeader;
oneTimePasswords = legacyHeader; oneTimePasswords = legacyHeader;
wallet = legacyHeader; // TODO: does this make any sense?
break; break;
case '0.1': case '0.1':
var headerData; var headerData;
@ -516,6 +536,22 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase') 'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
}); });
} }
if (typeof(headerData['wallet']) != 'undefined') {
wallet = new Clipperz.PM.DataModel.User.Header.Wallet({
'name': 'wallet',
'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase'),
'remoteData': {
'data': headerData['wallet']['data'],
'version': someServerData['version']
}
});
} else {
wallet = new Clipperz.PM.DataModel.User.Header.Wallet({
'name': 'wallet',
'retrieveKeyFunction': MochiKit.Base.method(this, 'getPassphrase')
});
}
break; break;
} }
@ -527,9 +563,10 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
'data': someServerData['header'], 'data': someServerData['header'],
'version': headerVersion, 'version': headerVersion,
'recordsIndex': recordsIndex, 'recordsIndex': recordsIndex,
'preferences': preferences, 'preferences': preferences,
'oneTimePasswords': oneTimePasswords 'oneTimePasswords': oneTimePasswords,
'wallet': wallet
} }
}; };
@ -552,7 +589,9 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
if (this._serverData == null) { if (this._serverData == null) {
innerDeferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'loadingUserDetails'); innerDeferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'loadingUserDetails');
innerDeferredResult.addMethod(this.connection(), 'message', 'getUserDetails'); innerDeferredResult.addMethod(this.connection(), 'message', 'getUserDetails');
// innerDeferredResult.addCallback(function (aValue) { console.log("USER DETAILS", aValue); return aValue; });
innerDeferredResult.addMethod(this, 'unpackServerData'); innerDeferredResult.addMethod(this, 'unpackServerData');
// innerDeferredResult.addCallback(function (aValue) { console.log("UNPACKED SERVER DATA", aValue); return aValue; });
innerDeferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'loadedUserDetails'); innerDeferredResult.addCallbackPass(MochiKit.Signal.signal, this, 'loadedUserDetails');
} }
@ -607,6 +646,7 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User, Object, {
'getHeaderIndex': function (aKey) { 'getHeaderIndex': function (aKey) {
return Clipperz.Async.callbacks("User.getHeaderIndex", [ return Clipperz.Async.callbacks("User.getHeaderIndex", [
MochiKit.Base.method(this, 'getServerData'), MochiKit.Base.method(this, 'getServerData'),
// function (aValue) { console.log("HEADER INDEX", aValue); return aValue; },
MochiKit.Base.itemgetter('header'), MochiKit.Base.itemgetter('header'),
MochiKit.Base.itemgetter(aKey) MochiKit.Base.itemgetter(aKey)
], {trace:false}) ], {trace:false})
@ -728,12 +768,7 @@ Clipperz.log("Warning: User.recordWithLabel('" + aLabel + "') is returning more
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
'getRecordDetail': function (aRecord) { 'getRecordDetail': function (aRecord) {
// return this.connection().message('getRecordDetail', {reference: aRecordReference}); return this.connection().message('getRecordDetail', {reference: aRecord.reference()});
return Clipperz.Async.callbacks("User.getRecordDetail", [
MochiKit.Base.method(this.connection(), 'message', 'getRecordDetail', {reference: aRecord.reference()}),
function(someInfo) { aRecord.setAttachmentServerStatus(someInfo['attachmentStatus']); return someInfo;}, // Couldn't find a better way...
], {trace:false});
}, },
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -906,7 +941,11 @@ Clipperz.log("Warning: User.recordWithLabel('" + aLabel + "') is returning more
'oneTimePasswords': [ 'oneTimePasswords': [
MochiKit.Base.method(this, 'getHeaderIndex', 'oneTimePasswords'), MochiKit.Base.method(this, 'getHeaderIndex', 'oneTimePasswords'),
MochiKit.Base.methodcaller(aMethodName, aValue) MochiKit.Base.methodcaller(aMethodName, aValue)
]//, ],
'wallet': [
MochiKit.Base.method(this, 'getHeaderIndex', 'wallet'),
MochiKit.Base.methodcaller(aMethodName, aValue)
]
// 'statistics': [ // 'statistics': [
// MochiKit.Base.method(this, 'getStatistics'), // MochiKit.Base.method(this, 'getStatistics'),
// MochiKit.Base.methodcaller(aMethodName, aValue) // MochiKit.Base.methodcaller(aMethodName, aValue)
@ -926,14 +965,14 @@ Clipperz.log("Warning: User.recordWithLabel('" + aLabel + "') is returning more
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
'getPreferences': function() { getPreferences: function() {
return Clipperz.Async.callbacks("User.getPreferences", [ return Clipperz.Async.callbacks("User.getPreferences", [
MochiKit.Base.method(this, 'getHeaderIndex', 'preferences'), MochiKit.Base.method(this, 'getHeaderIndex', 'preferences'),
MochiKit.Base.methodcaller('getPreferences') MochiKit.Base.methodcaller('getPreferences')
], {trace:false}); ], {trace:false});
}, },
'getPreference': function(aKey) { getPreference: function(aKey) {
return Clipperz.Async.callbacks("User.getPreference", [ return Clipperz.Async.callbacks("User.getPreference", [
MochiKit.Base.method(this, 'getHeaderIndex', 'preferences'), MochiKit.Base.method(this, 'getHeaderIndex', 'preferences'),
MochiKit.Base.methodcaller('getPreference', aKey) MochiKit.Base.methodcaller('getPreference', aKey)
@ -950,11 +989,7 @@ Clipperz.log("Warning: User.recordWithLabel('" + aLabel + "') is returning more
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
/*
'addNewAttachment': function(anAttachment) {
console.log("Adding attachment", anAttachment);
},
*/
'uploadAttachment': function(aRecordReference, anAttachmentReference, someData) { 'uploadAttachment': function(aRecordReference, anAttachmentReference, someData) {
// TODO: pass a callback to handle onProgress events (and modify Connection accordingly) // TODO: pass a callback to handle onProgress events (and modify Connection accordingly)
this.connection().message('uploadAttachment', { this.connection().message('uploadAttachment', {
@ -966,6 +1001,34 @@ Clipperz.log("Warning: User.recordWithLabel('" + aLabel + "') is returning more
//========================================================================= //=========================================================================
getWallet: function () {
return this.getHeaderIndex('wallet');
},
getUserMasterKey: function () {
//console.log("USER - GET USER MASTER KEY");
return Clipperz.Async.callbacks("User.getPreferences", [
MochiKit.Base.method(this, 'getHeaderIndex', 'wallet'),
MochiKit.Base.methodcaller('userMasterKey')
], {trace:false});
},
createCertificateForRecord: function (aRecord) {
var cardCertificatePath = 'm/0';
return Clipperz.Async.callbacks("User.createCertificateForRecord", [
MochiKit.Base.method(this, 'getWallet'),
MochiKit.Base.methodcaller('getNextID', cardCertificatePath),
MochiKit.Base.method(aRecord, 'setID'),
MochiKit.Base.method(aRecord, 'markAsCertified'),
MochiKit.Base.method(this, 'getWallet'),
MochiKit.Base.method(aRecord, 'computeCertificateInfo'),
function (certificateInfo) { return {'certificateInfo': certificateInfo}; },
], {trace:false});
},
//=========================================================================
'hasPendingChanges': function () { 'hasPendingChanges': function () {
var deferredResult; var deferredResult;
@ -1059,12 +1122,14 @@ Clipperz.log("Warning: User.recordWithLabel('" + aLabel + "') is returning more
deferredResult.addCallback(MochiKit.Base.bind(function (aResult, someHeaderPackedData) { deferredResult.addCallback(MochiKit.Base.bind(function (aResult, someHeaderPackedData) {
var header; var header;
//console.log("USER - prepareRemoteDataWithKey", someHeaderPackedData);
header = {}; header = {};
header['records'] = someHeaderPackedData['recordIndex']['records']; header['records'] = someHeaderPackedData['recordIndex']['records'];
header['directLogins'] = someHeaderPackedData['recordIndex']['directLogins']; header['directLogins'] = someHeaderPackedData['recordIndex']['directLogins'];
header['attachments'] = someHeaderPackedData['recordIndex']['attachments']; header['attachments'] = someHeaderPackedData['recordIndex']['attachments'];
header['preferences'] = {'data': someHeaderPackedData['preferences']['data']}; header['preferences'] = {'data': someHeaderPackedData['preferences']['data']};
header['oneTimePasswords'] = {'data': someHeaderPackedData['oneTimePasswords']['data']}; header['oneTimePasswords'] = {'data': someHeaderPackedData['oneTimePasswords']['data']};
header['wallet'] = {'data': someHeaderPackedData['wallet']['data']};
header['version'] = '0.1'; header['version'] = '0.1';
aResult['header'] = Clipperz.Base.serializeJSON(header); aResult['header'] = Clipperz.Base.serializeJSON(header);
@ -1089,10 +1154,17 @@ Clipperz.log("Warning: User.recordWithLabel('" + aLabel + "') is returning more
//========================================================================= //=========================================================================
'saveChanges': function () { 'saveChanges': function () {
return this.saveChangesWithExtraParameters();
},
'saveChangesWithExtraParameters': function (extraParameters) {
var deferredResult; var deferredResult;
var messageParameters; var messageParameters;
messageParameters = {}; messageParameters = {};
if (typeof(extraParameters) != 'undefined') {
messageParameters['extraParameters'] = extraParameters;
}
deferredResult = new Clipperz.Async.Deferred("User.saveChangaes", {trace:false}); deferredResult = new Clipperz.Async.Deferred("User.saveChangaes", {trace:false});
@ -1110,7 +1182,6 @@ Clipperz.log("Warning: User.recordWithLabel('" + aLabel + "') is returning more
deferredResult.addMethod(this, 'commitTransientState'); deferredResult.addMethod(this, 'commitTransientState');
deferredResult.addErrbackPass(MochiKit.Base.method(this, 'revertChanges')); deferredResult.addErrbackPass(MochiKit.Base.method(this, 'revertChanges'));
deferredResult.callback(); deferredResult.callback();
return deferredResult; return deferredResult;

View File

@ -130,10 +130,10 @@ Clipperz.Base.extend(Clipperz.PM.Proxy.JSON, Clipperz.PM.Proxy, {
deferredResult = new Clipperz.Async.Deferred("Proxy.JSON._sendMessage", {trace:false}); deferredResult = new Clipperz.Async.Deferred("Proxy.JSON._sendMessage", {trace:false});
//deferredResult.addCallback(function(){console.log("About to send request");}); //deferredResult.addCallback(function(){console.log("About to send request");});
deferredResult.addCallback(Clipperz.Async.doXHR, this.url(), { deferredResult.addCallback(Clipperz.Async.doXHR, this.url(), {
method:'POST', 'method':'POST',
sendContent:formData, 'sendContent':formData,
// headers:{"Content-Type":"application/x-www-form-urlencoded"}, // headers:{"Content-Type":"application/x-www-form-urlencoded"},
uploadProgress: aProgressCallback || null, 'uploadProgress': aProgressCallback || null,
}); });
//deferredResult.addCallback(function(something){console.log("Done sending request"); return something;}); //deferredResult.addCallback(function(something){console.log("Done sending request"); return something;});
deferredResult.addCallback(function (someValues) { deferredResult.addCallback(function (someValues) {

View File

@ -1031,6 +1031,7 @@ Clipperz.PM.Proxy.Offline.DataStore.defaultAccountInfo = {
'UPDATE_CREDENTIALS', 'UPDATE_CREDENTIALS',
'EDIT_CARD', 'EDIT_CARD',
'CARD_DETAILS', 'CARD_DETAILS',
'REGISTER_CARD',
'ADD_CARD', 'ADD_CARD',
'DELETE_CARD', 'DELETE_CARD',
'OFFLINE_COPY', 'OFFLINE_COPY',

View File

@ -25,11 +25,11 @@ refer to http://www.clipperz.com.
Clipperz.Base.module('Clipperz.PM.UI'); Clipperz.Base.module('Clipperz.PM.UI');
Clipperz.PM.UI.AttachmentController = function(someParameters) { Clipperz.PM.UI.AttachmentController = function(someParameters) {
this.MAX_SIMULTANEOUS_READ = 1; this.MAX_SIMULTANEOUS_READ = 1;
this.MAX_SIMULTANEOUS_UPLOAD = 1; this.MAX_SIMULTANEOUS_UPLOAD = 1;
this.MAX_SIMULTANEOUS_DOWNLOAD = 1; this.MAX_SIMULTANEOUS_DOWNLOAD = 1;
this.MAX_SIMULTANEOUS_ENCRYPT = 1; this.MAX_SIMULTANEOUS_ENCRYPT = 1;
this.MAX_SIMULTANEOUS_DECRYPT = 1; this.MAX_SIMULTANEOUS_DECRYPT = 1;
this.LATEST_ENCRYPTION_VERSION = '1.0'; // Versions aren't handled completely yet! this.LATEST_ENCRYPTION_VERSION = '1.0'; // Versions aren't handled completely yet!
@ -74,7 +74,11 @@ MochiKit.Base.update(Clipperz.PM.UI.AttachmentController.prototype, {
//========================================================================= //=========================================================================
addAttachment: function (anAttachment) { addAttachment: function (anAttachment) {
var deferredResult; var deferredResult;
var actualDeferredResult;
actualDeferredResult = new Clipperz.Async.Deferred("Clipperz.PM.UI.AttachmentController.uploadAttachment-result", {trace:false});
actualDeferredResult.addMethod(anAttachment, 'setValue', 'hash');
deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.UI.AttachmentController.uploadAttachment", {trace:false}); deferredResult = new Clipperz.Async.Deferred("Clipperz.PM.UI.AttachmentController.uploadAttachment", {trace:false});
deferredResult.collectResults({ deferredResult.collectResults({
@ -89,10 +93,12 @@ MochiKit.Base.update(Clipperz.PM.UI.AttachmentController.prototype, {
'recordReference': MochiKit.Base.method(anAttachment.record(), 'reference'), 'recordReference': MochiKit.Base.method(anAttachment.record(), 'reference'),
'process': MochiKit.Base.partial(MochiKit.Async.succeed, 'UPLOAD'), // Used only to differentiate notifications 'process': MochiKit.Base.partial(MochiKit.Async.succeed, 'UPLOAD'), // Used only to differentiate notifications
}, {trace: false}); }, {trace: false});
deferredResult.addCallback(function (someInfo) { someInfo['deferredResult'] = actualDeferredResult; return someInfo; });
deferredResult.addMethod(this, 'addFileToQueue'); deferredResult.addMethod(this, 'addFileToQueue');
deferredResult.callback(); deferredResult.callback();
return deferredResult; // return deferredResult;
return actualDeferredResult;
}, },
getAttachment: function(anAttachment, aMessageCallback) { getAttachment: function(anAttachment, aMessageCallback) {
@ -162,8 +168,8 @@ MochiKit.Base.update(Clipperz.PM.UI.AttachmentController.prototype, {
processNextElements = true; processNextElements = true;
for (i in this.fileQueue) { for (i in this.fileQueue) {
if(processNextElements) { if (processNextElements) {
currentElement = this.fileQueue[i]; currentElement = this.fileQueue[i];
switch (currentElement['status']) { switch (currentElement['status']) {
case 'WAITING_READ': case 'WAITING_READ':
if ((count['READING']) < this.MAX_SIMULTANEOUS_READ) { if ((count['READING']) < this.MAX_SIMULTANEOUS_READ) {
@ -214,20 +220,20 @@ MochiKit.Base.update(Clipperz.PM.UI.AttachmentController.prototype, {
var count; var count;
count = { count = {
'WAITING_READ': 0, 'WAITING_READ': 0,
'READING': 0, 'READING': 0,
'WAITING_ENCRYPT': 0, 'WAITING_ENCRYPT': 0,
'ENCRYPTING': 0, 'ENCRYPTING': 0,
'WAITING_UPLOAD': 0, 'WAITING_UPLOAD': 0,
'UPLOADING': 0, 'UPLOADING': 0,
'WAITING_DOWNLOAD': 0, 'WAITING_DOWNLOAD': 0,
'DOWNLOADING': 0, 'DOWNLOADING': 0,
'WAITING_DECRYPT': 0, 'WAITING_DECRYPT': 0,
'DECRYPTING': 0, 'DECRYPTING': 0,
'WAITING_SAVE': 0, 'WAITING_SAVE': 0,
'DONE': 0, 'DONE': 0,
'CANCELED': 0, 'CANCELED': 0,
'FAILED': 0, 'FAILED': 0,
}; };
for (var i in this.fileQueue) { for (var i in this.fileQueue) {
@ -332,13 +338,19 @@ MochiKit.Base.update(Clipperz.PM.UI.AttachmentController.prototype, {
}, },
readFileOnload: function(aFileReference, anEvent) { readFileOnload: function(aFileReference, anEvent) {
var fileContent;
var fileContentSha256Hash;
fileContent = new Uint8Array(anEvent.target.result);
fileContentSha256Hash = npm.bitcoin.crypto.sha256(fileContent).toString('hex');
this.getQueueElement(aFileReference)['deferredResult'].callback(fileContentSha256Hash);
this.updateFileInQueue(aFileReference, { this.updateFileInQueue(aFileReference, {
'status': 'WAITING_ENCRYPT', 'status': 'WAITING_ENCRYPT',
'originalArray': new Uint8Array(anEvent.target.result), 'originalArray': fileContent,
}) })
}, },
//========================================================================= //=========================================================================
// Queue Processing: ENCRYPT // Queue Processing: ENCRYPT
//========================================================================= //=========================================================================
@ -349,11 +361,11 @@ MochiKit.Base.update(Clipperz.PM.UI.AttachmentController.prototype, {
}); });
this.cryptoObject.subtle.importKey( this.cryptoObject.subtle.importKey(
"raw", "raw",
aKey, //this is an example jwk key, "raw" would be an ArrayBuffer aKey, //this is an example jwk key, "raw" would be an ArrayBuffer
{ name: "AES-CBC" }, //this is the algorithm options { name: "AES-CBC" }, //this is the algorithm options
false, //whether the key is extractable (i.e. can be used in exportKey) false, //whether the key is extractable (i.e. can be used in exportKey)
["encrypt"] //can be "encrypt", "decrypt", "wrapKey", or "unwrapKey" ["encrypt"] //can be "encrypt", "decrypt", "wrapKey", or "unwrapKey"
) )
// .then(MochiKit.Base.method(this, 'doEncrypt', aFileReference, anArrayBuffer, aNonce)) // .then(MochiKit.Base.method(this, 'doEncrypt', aFileReference, anArrayBuffer, aNonce))
.then(this.doEncrypt.bind(this,aFileReference, anArrayBuffer, aNonce)) .then(this.doEncrypt.bind(this,aFileReference, anArrayBuffer, aNonce))

File diff suppressed because one or more lines are too long

View File

@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components');
Clipperz.PM.UI.Components.AccountStatusClass = React.createClass({ Clipperz.PM.UI.Components.AccountStatusClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.AccountStatus',
propTypes: { propTypes: {
// 'currentSubscriptionType': React.PropTypes.oneOf(['EARLY_ADOPTER', 'FRIEND', 'FAN', 'DEVOTEE', 'PATRON', 'TRIAL', 'TRIAL_EXPIRED', 'PAYMENT_FAILED_2', 'EXPIRED', 'PAYMENT_FAILED', 'VERIFYING_PAYMENT', 'VERIFYING_PAYMENT_2']).isRequired, // 'currentSubscriptionType': React.PropTypes.oneOf(['EARLY_ADOPTER', 'FRIEND', 'FAN', 'DEVOTEE', 'PATRON', 'TRIAL', 'TRIAL_EXPIRED', 'PAYMENT_FAILED_2', 'EXPIRED', 'PAYMENT_FAILED', 'VERIFYING_PAYMENT', 'VERIFYING_PAYMENT_2']).isRequired,
'expirationDate': React.PropTypes.string /* .isRequired */, 'expirationDate': React.PropTypes.string /* .isRequired */,
@ -54,15 +56,15 @@ Clipperz.PM.UI.Components.AccountStatusClass = React.createClass({
proxyInfoClasses[this.props['proxyType']] = true; proxyInfoClasses[this.props['proxyType']] = true;
proxyInfoClasses['withReferenceDate'] = (this.props['referenceDate'] != null); proxyInfoClasses['withReferenceDate'] = (this.props['referenceDate'] != null);
return React.DOM.div({'className':'miscInfo'}, [ return React.DOM.div({'key':'miscInfo', 'className':'miscInfo'}, [
React.DOM.div({'className':Clipperz.PM.UI.Components.classNames(proxyInfoClasses)}, [ React.DOM.div({'key':'miscInfo_1', 'className':Clipperz.PM.UI.Components.classNames(proxyInfoClasses)}, [
React.DOM.span({'className':'proxyDescription'}, this.props['proxyTypeDescription']), React.DOM.span({'key':'proxyDescription', 'className':'proxyDescription'}, this.props['proxyTypeDescription']),
React.DOM.span({'className':'referenceDate'}, this.props['referenceDate']) React.DOM.span({'key':'referenceDate', 'className':'referenceDate'}, this.props['referenceDate'])
]), ]),
React.DOM.div({'className':Clipperz.PM.UI.Components.classNames(accountInfoClasses)}, [ React.DOM.div({'key':'miscInfo_2', 'className':Clipperz.PM.UI.Components.classNames(accountInfoClasses)}, [
React.DOM.span({'className':'level'}, Clipperz.PM.DataModel.Feature['featureSets'][this.props['featureSet']]), React.DOM.span({'key':'level', 'className':'level'}, Clipperz.PM.DataModel.Feature['featureSets'][this.props['featureSet']]),
React.DOM.span({'className':'expirationMessage'}, "expiring on"), React.DOM.span({'key':'expirationMessage', 'className':'expirationMessage'}, "expiring on"),
React.DOM.span({'className':'expirationDate'}, this.props['expirationDate']) React.DOM.span({'key':'expirationDate', 'className':'expirationDate'}, this.props['expirationDate'])
]) ])
]); ]);

View File

@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components');
Clipperz.PM.UI.Components.AttachmentQueueBoxClass = React.createClass({ Clipperz.PM.UI.Components.AttachmentQueueBoxClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.AttachmentQueueBox',
propTypes: { propTypes: {
'attachmentQueueInfo': React.PropTypes.object.isRequired, 'attachmentQueueInfo': React.PropTypes.object.isRequired,
'attachmentQueueBoxStatus': React.PropTypes.string.isRequired, 'attachmentQueueBoxStatus': React.PropTypes.string.isRequired,
@ -104,7 +106,7 @@ Clipperz.PM.UI.Components.AttachmentQueueBoxClass = React.createClass({
render: function () { render: function () {
//test //test
this.renderNotifications(this.props['attachmentQueueInfo']['notifications']); // this.renderNotifications(this.props['attachmentQueueInfo']['notifications']);
return React.DOM.div({ return React.DOM.div({
'className': 'attachmentQueueStatus '+this.props['attachmentQueueBoxStatus'], 'className': 'attachmentQueueStatus '+this.props['attachmentQueueBoxStatus'],

View File

@ -26,13 +26,15 @@ Clipperz.Base.module('Clipperz.PM.UI.Components');
Clipperz.PM.UI.Components.ButtonClass = React.createClass({ Clipperz.PM.UI.Components.ButtonClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.Button',
propTypes: { propTypes: {
'eventName': React.PropTypes.string.isRequired, 'eventName': React.PropTypes.string.isRequired,
'label': React.PropTypes.string.isRequired, 'label': React.PropTypes.string.isRequired,
'handler': React.PropTypes.func.isRequired, 'handler': React.PropTypes.func.isRequired,
'className': React.PropTypes.string, 'className': React.PropTypes.string,
'badgeTopContent': React.PropTypes.string, 'badgeTopContent': React.PropTypes.number,
'badgeBottomContent': React.PropTypes.string, 'badgeBottomContent': React.PropTypes.number,
}, },
//========================================================================= //=========================================================================

View File

@ -25,14 +25,16 @@ Clipperz.Base.module('Clipperz.PM.UI.Components');
Clipperz.PM.UI.Components.CardToolbarClass = React.createClass({ Clipperz.PM.UI.Components.CardToolbarClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.CardToolbar',
propTypes: { propTypes: {
// 'style': React.PropTypes.oneOf(['extra-short', 'narrow', 'wide', 'extra-wide']).isRequired, // 'style': React.PropTypes.oneOf(['extra-short', 'narrow', 'wide', 'extra-wide']).isRequired,
'style': React.PropTypes.oneOf(Clipperz_PM_UI_availableStyles).isRequired, 'style': React.PropTypes.oneOf(Clipperz_PM_UI_availableStyles).isRequired,
'enableSidePanels': React.PropTypes.bool.isRequired, 'enableSidePanels': React.PropTypes.bool.isRequired,
'accountInfo': React.PropTypes.object.isRequired, 'accountInfo': React.PropTypes.object.isRequired,
'proxyInfo': React.PropTypes.object.isRequired, 'proxyInfo': React.PropTypes.object.isRequired,
'messageBox': React.PropTypes.object.isRequired, 'messageBox': React.PropTypes.object.isRequired,
'filter': React.PropTypes.object /*.isRequired */, 'filter': React.PropTypes.object /*.isRequired */,
'attachmentQueueInfo': React.PropTypes.object.isRequired, 'attachmentQueueInfo': React.PropTypes.object.isRequired,
}, },
@ -55,6 +57,12 @@ Clipperz.PM.UI.Components.CardToolbarClass = React.createClass({
//============================================================================ //============================================================================
certificateQueueToggleHandler: function (anEvent) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'toggleCertificateQueueBox');
},
//============================================================================
renderWithSidePanels: function () { renderWithSidePanels: function () {
var attachmentDownloadNotificationNumber = MochiKit.Base.filter(function(anElement) { var attachmentDownloadNotificationNumber = MochiKit.Base.filter(function(anElement) {
return anElement['queueElement']['process'] == 'DOWNLOAD'; return anElement['queueElement']['process'] == 'DOWNLOAD';
@ -62,18 +70,25 @@ Clipperz.PM.UI.Components.CardToolbarClass = React.createClass({
var attachmentUploadNotificationNumber = this.props['attachmentQueueInfo']['notifications'].length - attachmentDownloadNotificationNumber; var attachmentUploadNotificationNumber = this.props['attachmentQueueInfo']['notifications'].length - attachmentDownloadNotificationNumber;
// attachmentDownloadNotificationNumber = 2;
// attachmentUploadNotificationNumber = 3;
var verifyingCertificateNotificationNumber = this.props['certificateQueueInfo'] ? MochiKit.Base.filter(function (anCertificationInfo) {
return anCertificationInfo['status'] == 'requested';
}, this.props['certificateQueueInfo']).length : 0;
var verifiedCertificateNotificationNumber = this.props['certificateQueueInfo'] ? MochiKit.Base.filter(function (anCertificationInfo) {
return anCertificationInfo['status'] == 'published';
}, this.props['certificateQueueInfo']).length : 0;
return [ return [
React.DOM.div({className:'selectionToggle'}, [ React.DOM.div({className:'selectionToggle'}, [
Clipperz.PM.UI.Components.Button({eventName:'selectionToggleButton', label:"tags", handler:this.selectionToggleHandler}) Clipperz.PM.UI.Components.Button({eventName:'selectionToggleButton', label:"tags", handler:this.selectionToggleHandler})
]), ]),
this.renderWithoutSidePanels(), this.renderWithoutSidePanels(),
// React.DOM.div({className:'attachmentToggle'}, [
// Clipperz.PM.UI.Components.Button({eventName:'attachmentQueueToggleButton', label:"clipperz", handler:this.attachmentQueueToggleHandler})
// ]),
// TODO: validate and adjust names // TODO: validate and adjust names
React.DOM.div({className:'settingsToggle'}, [ React.DOM.div({className:'settingsToggle'}, [
Clipperz.PM.UI.Components.Button({eventName:'attachmentQueueToggleButton', label:"\u2191\u2193", handler:this.attachmentQueueToggleHandler, badgeTopContent: attachmentDownloadNotificationNumber, badgeBottomContent: attachmentUploadNotificationNumber}), Clipperz.PM.UI.Components.Button({eventName:'certificateQueueToggleButton', label:"certificate", handler:this.certificateQueueToggleHandler, badgeTopContent:verifyingCertificateNotificationNumber, badgeBottomContent:verifiedCertificateNotificationNumber}),
Clipperz.PM.UI.Components.Button({eventName:'attachmentQueueToggleButton', label:"\u2191\u2193", handler:this.attachmentQueueToggleHandler, badgeTopContent:attachmentDownloadNotificationNumber, badgeBottomContent:attachmentUploadNotificationNumber}),
Clipperz.PM.UI.Components.Button({eventName:'settingsToggleButton', label:"menu", handler:this.settingsToggleHandler}) Clipperz.PM.UI.Components.Button({eventName:'settingsToggleButton', label:"menu", handler:this.settingsToggleHandler})
]) ])
]; ];
@ -81,6 +96,7 @@ Clipperz.PM.UI.Components.CardToolbarClass = React.createClass({
renderWithoutSidePanels: function () { renderWithoutSidePanels: function () {
var result; var result;
//console.log("CARD TOOLBAR", this.props);
if (this.props['filter']) { if (this.props['filter']) {
//console.log("CARD TOOLBAR", this.props['filter']['type']); //console.log("CARD TOOLBAR", this.props['filter']['type']);

View File

@ -0,0 +1,221 @@
/*
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.Cards');
var textHeight = 12;
var outputSpacing = 8;
var arrowLength = 70;
var arrowWidth = 8;
var arrowHalfHeight = 2;
Clipperz.PM.UI.Components.Cards.CertificateRendererClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.Cards.CertificateRenderer',
//==============================================================================
renderTransactionSchema: function () {
var outputDistance = 10;
// var numberOfAttachments = this.props['attachments'].length;
var numberOfAttachments = 0;
var numberOfOutputs = 1 + 1 + numberOfAttachments + 1;
var height = numberOfOutputs * (textHeight + outputSpacing) + outputDistance;
var rectWidth = arrowLength * 2;
var arrow = function (x, y) {
var pathItems = function (items) {
return (MochiKit.Base.map(function (coordinates) { return coordinates[0] + "," + coordinates[1]; }, items)).join(" ");
}
return [
React.DOM.line({'x1':x, 'y1':y, 'x2':x + arrowLength, 'y2':y, 'stroke':'black', 'strokeWidth':1}),
React.DOM.polygon({'points':pathItems([[x + arrowLength, y], [x + arrowLength - arrowWidth, y + arrowHalfHeight], [x + arrowLength - arrowWidth, y - arrowHalfHeight]]), 'fill':'black', 'stroke':'black', 'strokeWidth':1}),
];
};
var outputArrow = function (args) {
var index = args[0];
var label = args[1];
return [
// arrow(arrowLength + rectWidth, ((index + 0.5) * (textHeight + outputSpacing))),
React.DOM.text({'x':(2 * arrowLength) + rectWidth + 15, 'y':(((index + 1) * textHeight) + (index + 0.5) * outputSpacing), 'fill':'black'}, label),
];
};
return React.DOM.svg({'viewBox':'0 0 600 ' + height, 'width':'100%', 'height':height, 'fill':'currentcolor'}, [
arrow(0, height/2),
React.DOM.rect({'x':arrowLength, 'y':0, 'width':rectWidth, 'height':height, 'fill':'blue', 'opacity':0.3}),
React.DOM.rect({'x':arrowLength, 'y':0, 'width':rectWidth, 'height':height, 'fill':'none', 'stroke':'black', 'strokeWidth':1, 'opacity':1}),
React.DOM.g({'transform':'matrix(-0.2, 0, 0, ' + ((numberOfOutputs - 1) * 0.1225) + ', ' + ((arrowLength * 4) + 10) +', 0)'}, [
React.DOM.path({'d':'M 19.8,25.8 C 19.8,11.2 15.6,2.2 0,0.4 L 0.4,0 C 23,0.4 29.2,7.2 29.2,29 L 29.2,59.2 C 29.2,72.6 30.6,79 45.2,82.6 L 45.2,83 C 30.8,86.6 29.2,93 29.2,106.2 L 29.2,138.4 C 29.2,159.4 21.4,165.4 0.4,166 L 0,165.601 C 16,163.201 19.8,155.201 19.8,140 L 19.8,107.8 C 19.8,94.2 21.6,86.4 36.6,83 L 36.6,82.6 C 21.4,79 19.8,70.6 19.8,57 L 19.8,25.8 z '})
]),
arrow((arrowLength + rectWidth), ((numberOfOutputs - 1) * (textHeight + outputSpacing) / 2)),
React.DOM.text({'x':(arrowLength + rectWidth) + 5, 'y':((numberOfOutputs - 1) * (textHeight + outputSpacing) / 2) - 2, 'fill':'black', 'style':{'fontSize':'0.6em'}}, 'MULTI-SIG'),
arrow((arrowLength + rectWidth), ((numberOfOutputs - 0.5) * (textHeight + outputSpacing)) + outputDistance),
React.DOM.text({'x':(arrowLength + rectWidth) + 5, 'y':((numberOfOutputs - 0.5) * (textHeight + outputSpacing)) - 2 + outputDistance, 'fill':'black', 'style':{'fontSize':'0.6em'}}, 'OP_RETURN'),
React.DOM.text({'x':(2 * arrowLength) + rectWidth + 5, 'y':((numberOfOutputs * textHeight) + (numberOfOutputs - 0.5) * outputSpacing) + outputDistance, 'fill':'black'}, '"CLIPPERZ ' + this.props['certificateInfo']['version'] + ' REG"'),
this.props['certificateDetails'] ? MochiKit.Base.map(outputArrow,
MochiKit.Base.zip(
MochiKit.Iter.range(0, numberOfOutputs),
[this.props['certificateDetails']['transaction']['card.address'], this.props['certificateDetails']['transaction']['metadata.address']]
/*
MochiKit.Base.concat(
[this.props['certificateDetails']['transaction']['card.address'], this.props['certificateDetails']['transaction']['metadata.address']],
MochiKit.Base.map(
MochiKit.Base.itemgetter('address'),
MochiKit.Base.values(this.props['certificateDetails']['transaction']['attachments'])
)
)
*/
)
): null,
]);
},
//==============================================================================
renderCertificateDetails: function () {
return React.DOM.ul({'className':'transactionInfo'}, [
React.DOM.li({}, /*"OUT00 - " + */"BTC address of card: " + this.props['certificateDetails']['transaction']['card.address']),
React.DOM.li({}, [
React.DOM.div({'className':'metadata'}, [
React.DOM.header({}, 'Card data'),
React.DOM.dl({'className':'title'}, [React.DOM.dt({}, "Title"), React.DOM.dd({}, this.props['certificateDetails']['metadata']['label'])]),
MochiKit.Base.map(function (aField) { return React.DOM.dl({'className':'field'}, [React.DOM.dt({}, aField['label']), React.DOM.dd({}, aField['value'])]); }, this.props['certificateDetails']['metadata']['fields']),
this.props['certificateDetails']['metadata']['notes'] ? React.DOM.dl({'className':'notes'}, [React.DOM.dt({}, "Notes"), React.DOM.dd({}, this.props['certificateDetails']['metadata']['notes'])]) : null,
React.DOM.ul({'className':'attachments'},
MochiKit.Base.map(
function (anAttachmentInfo) {
var numberPadding = function (aValue) {
return ("00" + aValue).substr(-2);
}
return React.DOM.li({}, [
React.DOM.dl({'className':'file'}, [React.DOM.dt({}, "File"), React.DOM.dd({}, anAttachmentInfo[0]['name'])]),
React.DOM.dl({'className':'size'}, [React.DOM.dt({}, "Size"), React.DOM.dd({}, filesize(anAttachmentInfo[0]['size']))]),
React.DOM.dl({'className':'type'}, [React.DOM.dt({}, "Filetype"), React.DOM.dd({}, anAttachmentInfo[0]['contentType'])]),
React.DOM.dl({'className':'hash'}, [React.DOM.dt({}, "Sha256"), React.DOM.dd({}, anAttachmentInfo[1]['hash'])]),
// React.DOM.div({'className':'address'}, /*"OUT" + numberPadding(anAttachmentInfo[2]) + " - " + */"File BTC address: " + anAttachmentInfo[1]['address'])
]);
}, MochiKit.Base.zip(
this.props['certificateDetails']['metadata']['attachments'],
MochiKit.Base.values(this.props['certificateDetails']['transaction']['attachments']),
MochiKit.Iter.range(2, this.props['certificateDetails']['metadata']['attachments'].length + 2)
)
)
),
React.DOM.div({'className':'address'}, /*"OUT01 - " + */"BTC address from card data: " + this.props['certificateDetails']['transaction']['metadata.address'])
])
])
]);
},
renderSpinner: function () {
return React.DOM.div({'className':'spinner'}, [
React.DOM.div({'className':'bar01'}),
React.DOM.div({'className':'bar02'}),
React.DOM.div({'className':'bar03'}),
React.DOM.div({'className':'bar04'}),
React.DOM.div({'className':'bar05'}),
React.DOM.div({'className':'bar06'}),
React.DOM.div({'className':'bar07'}),
React.DOM.div({'className':'bar08'}),
React.DOM.div({'className':'bar09'}),
React.DOM.div({'className':'bar10'}),
React.DOM.div({'className':'bar11'}),
React.DOM.div({'className':'bar12'}),
]);
},
componentDidMount: function () {
// this.renderTransactionDiagram(this.refs['canvas']);
},
render: function () {
//console.log("CERTIFICATE RENDERER", this.props, NETWORK);
console.log("CERTIFICATE RENDERER", this.props);
var transactionInspectorPath = (NETWORK.pubKeyHash == 111) ? 'tBTC' : 'BTC';
var certificateInfo;
if (this.props['certificateDetails']) {
certificateInfo = this.props['certificateDetails'];
certificateInfo['tx'] = this.props['certificateInfo']['txID'];
certificateInfo['requestDate'] = this.props['certificateInfo']['requestDate'];
certificateInfo['creationDate'] = this.props['certificateInfo']['creationDate'];
} else {
certificateInfo = null;
}
return React.DOM.div({'className':'certificateContent'}, [
React.DOM.div({}, [
React.DOM.header({}, [
React.DOM.div({'className':'title'}, [
React.DOM.h3({}, "clipperz"),
React.DOM.h1({}, "Blockchain certificate")
]),
React.DOM.div({'className':'info'}, [
// React.DOM.dl({'className':'cardLabel'}, [React.DOM.dt({}, "Card"), React.DOM.dd({}, this.props['label'])]),
React.DOM.dl({'className':'cardLabel'}, [React.DOM.dt({}, "Card"), React.DOM.dd({}, this.props['certificateDetails'] ? this.props['certificateDetails']['metadata']['label'] : "")]),
React.DOM.dl({}, [React.DOM.dt({}, "Requested on"), React.DOM.dd({}, (new XDate(this.props['certificateInfo']['requestDate'])).toString("MMM d, yyyy - HH:mm"))]),
React.DOM.dl({}, [React.DOM.dt({}, "Validated on"), React.DOM.dd({}, (new XDate(this.props['certificateInfo']['creationDate'])).toString("MMM d, yyyy - HH:mm"))]),
React.DOM.dl({'className':'version'}, [React.DOM.dt({}, "Clipperz protocol version"), React.DOM.dd({}, this.props['certificateInfo']['version'])]),
]),
]),
React.DOM.div({'className':'details'}, this.props['certificateDetails'] ? this.renderCertificateDetails() : this.renderSpinner()),
]),
React.DOM.div({'className':'transactionInfo'}, [
React.DOM.div({'className':'description'}, [
React.DOM.p({}, "The following transaction has been added to the Bitcoin blockchain."),
React.DOM.p({}, [
React.DOM.span({}, "TX ID: "),
React.DOM.a({'href':'https://clipperz.is/tx/' + transactionInspectorPath + '/' + this.props['certificateInfo']['txID']}, this.props['certificateInfo']['txID'])
]),
]),
this.renderTransactionSchema(),
]),
React.DOM.div({'className':'reviewInfo'}, [
React.DOM.p({}, '----'),
React.DOM.p({'className':'verify'}, [
React.DOM.span({}, "You can check the authenticity of this certificate at "),
React.DOM.a({'href':'https://clipperz.is/verify'}, "clipperz.is/verify")
]),
React.DOM.p({'className':'instructions'}, [
React.DOM.span({}, "If you want to perform this check by yourself, just follow "),
React.DOM.a({'href':'https://clipperz.is/verify_howto'}, "these instructions")
]),
]),
certificateInfo ? React.DOM.textarea({'className':'certificateDetails', 'value':Clipperz.Base.serializeJSON(certificateInfo), 'readOnly':true}) : null,
]);
},
//===========================================================================
});
Clipperz.PM.UI.Components.Cards.CertificateRenderer = React.createFactory(Clipperz.PM.UI.Components.Cards.CertificateRendererClass);

View File

@ -28,10 +28,12 @@ Clipperz.PM.UI.Components.Cards.CommandToolbarClass = React.createClass({
//============================================================================ //============================================================================
displayName: 'Clipperz.PM.UI.Components.Cards.CommandToolbar',
propTypes: { propTypes: {
// 'label': React.PropTypes.string.isRequired, // 'label': React.PropTypes.string.isRequired,
// 'loading': React.PropTypes.bool, // 'loading': React.PropTypes.bool,
'features': React.PropTypes.array.isRequired, 'features': React.PropTypes.array.isRequired,
}, },
features: function () { features: function () {
@ -42,6 +44,10 @@ Clipperz.PM.UI.Components.Cards.CommandToolbarClass = React.createClass({
return (this.features().indexOf(aValue) > -1); return (this.features().indexOf(aValue) > -1);
}, },
isCardCertified: function () {
return ((typeof(this.props['certificateInfo']) != 'undefined') && (this.props['certificateInfo'] != null));
},
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
getInitialState: function() { getInitialState: function() {
@ -57,9 +63,10 @@ Clipperz.PM.UI.Components.Cards.CommandToolbarClass = React.createClass({
return { return {
'delete': { 'label': "delete", 'broadcastEvent': 'deleteCard', 'enabled': this.isFeatureEnabled('DELETE_CARD')}, 'delete': { 'label': "delete", 'broadcastEvent': 'deleteCard', 'enabled': this.isFeatureEnabled('DELETE_CARD')},
'archive': { 'label': archiveLabel, 'broadcastEvent': 'toggleArchiveCard', 'enabled': this.isFeatureEnabled('EDIT_CARD')}, 'archive': { 'label': archiveLabel, 'broadcastEvent': 'toggleArchiveCard', 'enabled': this.isFeatureEnabled('EDIT_CARD')},
// 'share': { 'label': "share", 'broadcastEvent': 'shareCard' }, // 'share': { 'label': "share", 'broadcastEvent': 'shareCard' },
'clone': { 'label': "clone", 'broadcastEvent': 'cloneCard', 'enabled': this.isFeatureEnabled('ADD_CARD')}, 'clone': { 'label': "clone", 'broadcastEvent': 'cloneCard', 'enabled': this.isFeatureEnabled('ADD_CARD')},
'edit': { 'label': "edit", 'broadcastEvent': 'editCard', 'enabled': this.isFeatureEnabled('EDIT_CARD')} 'register': { 'label': "register", 'broadcastEvent': 'createCertificate', 'enabled': this.isFeatureEnabled('REGISTER_CARD') && !this.isCardCertified()},
'edit': { 'label': "edit", 'broadcastEvent': 'editCard', 'enabled': this.isFeatureEnabled('EDIT_CARD') && !this.isCardCertified()}
}; };
}, },

View File

@ -25,23 +25,39 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.Cards');
Clipperz.PM.UI.Components.Cards.DetailClass = React.createClass({ Clipperz.PM.UI.Components.Cards.DetailClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.Cards.Detail',
propTypes: { propTypes: {
'allTags': React.PropTypes.array, 'allTags': React.PropTypes.array,
}, },
viewComponentProps: function () { viewComponentProps: function () {
var result; var result;
var props = this.props;
var propertiesToPassAlong = [
'features',
'style',
'showGlobalMask',
'allTags',
'preferences',
'attachmentQueueInfo',
'proxyInfo',
'showCertificatePreview',
'certificateDetails'
];
result = this.props['selectedCard']; result = props['selectedCard'];
if (result) { if (result) {
result['features'] = this.props['features']; // result['features'] = this.props['features'];
result['style'] = this.props['style']; // result['style'] = this.props['style'];
result['ask'] = (this.props['style'] == 'narrow') ? this.props['ask'] : null; result['ask'] = (props['style'] == 'narrow') ? props['ask'] : null;
result['showGlobalMask'] = this.props['showGlobalMask']; // result['showGlobalMask'] = this.props['showGlobalMask'];
result['allTags'] = this.props['allTags']; // result['allTags'] = this.props['allTags'];
result['preferences'] = this.props['preferences']; // result['preferences'] = this.props['preferences'];
result['attachmentQueueInfo'] = this.props['attachmentQueueInfo']; // result['attachmentQueueInfo'] = this.props['attachmentQueueInfo'];
result['proxyInfo'] = this.props['proxyInfo']; // result['proxyInfo'] = this.props['proxyInfo'];
// result['showCertificatePreview'] = this.props['showCertificatePreview'];
MochiKit.Iter.forEach(propertiesToPassAlong, function (aProperty) { result[aProperty] = props[aProperty]; });
} }
return result; return result;

View File

@ -28,6 +28,8 @@ Clipperz.PM.UI.Components.Cards.EditClass = React.createClass({
//============================================================================ //============================================================================
displayName: 'Clipperz.PM.UI.Components.Cards.Edit',
propTypes: { propTypes: {
'allTags': React.PropTypes.array, 'allTags': React.PropTypes.array,
// 'label': React.PropTypes.string /*.isRequired */ , // 'label': React.PropTypes.string /*.isRequired */ ,
@ -128,7 +130,7 @@ console.log("DROP"); //, anEvent);
], {trace:false}); ], {trace:false});
} else { } else {
//console.log("CANCELLED FIELD MOVE"); //console.log("CANCELED FIELD MOVE");
} }
// Delayed because a quick touch would prevent the state to update correctly otherwise (don't know why) // Delayed because a quick touch would prevent the state to update correctly otherwise (don't know why)
@ -453,7 +455,7 @@ console.log("DROP"); //, anEvent);
}, },
removeDirectLogin: function(aDirectLoginReference) { removeDirectLogin: function(aDirectLoginReference) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'removeDirectLogin', this.record(), aDirectLoginReference); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'removeDirectLogin', {'record':this.record(), 'directLoginReference':aDirectLoginReference});
}, },
//============================================================================ //============================================================================
@ -614,7 +616,7 @@ console.log("DROP"); //, anEvent);
handleRemoveAttachment: function(anAttachment) { handleRemoveAttachment: function(anAttachment) {
// MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'cancelAttachment', anAttachment); // MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'cancelAttachment', anAttachment);
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'removeAttachment', this.record(), anAttachment); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'removeAttachment', {'record':this.record(), 'attachment': anAttachment});
}, },
//............................................................................ //............................................................................
@ -622,13 +624,15 @@ console.log("DROP"); //, anEvent);
uploadFiles: function(someFiles) { uploadFiles: function(someFiles) {
var i; var i;
//console.log("uploadFiles", someFiles);
var newSkippedFiles = []; var newSkippedFiles = [];
for (i = 0; i < someFiles.length; i++) { for (i = 0; i < someFiles.length; i++) {
var file = someFiles[i]; var file = someFiles[i];
//console.log("uploadFiles - file", file);
if (file.size <= Clipperz.PM.DataModel.Attachment.MAX_ATTACHMENT_SIZE) { if (file.size <= Clipperz.PM.DataModel.Attachment.MAX_ATTACHMENT_SIZE) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'addAttachment', this.record(), file); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'addAttachment', {'record':this.record(), 'file':file});
} else { } else {
newSkippedFiles.push(file); newSkippedFiles.push(file);
this.setState({'skippedFiles': newSkippedFiles}); this.setState({'skippedFiles': newSkippedFiles});
@ -636,7 +640,7 @@ console.log("DROP"); //, anEvent);
} }
// TODO: check compatibility with all browsers // TODO: check compatibility with all browsers
this.refs['attachmentInput'].getDOMNode().value = null; this.refs['attachmentInput'].value = null;
}, },
//............................................................................ //............................................................................
@ -658,12 +662,14 @@ console.log("DROP"); //, anEvent);
// http://enome.github.io/javascript/2014/03/24/drag-and-drop-with-react-js.html // 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 // https://code.google.com/p/chromium/issues/detail?id=168387
// http://www.quirksmode.org/blog/archives/2009/09/the_html5_drag.html // http://www.quirksmode.org/blog/archives/2009/09/the_html5_drag.html
anEvent.stopPropagation();
anEvent.preventDefault(); anEvent.preventDefault();
anEvent.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
}, },
//............................................................................ //............................................................................
renderSkippedFiles: function() { renderSkippedFiles: function () {
var result; var result;
result = null; result = null;
@ -687,7 +693,7 @@ console.log("DROP"); //, anEvent);
return result; return result;
}, },
renderAttachmentProgress: function(aStatus, aServerStatus, aProgress) { renderAttachmentProgress: function (aStatus, aServerStatus, aProgress) {
var result; var result;
var queueOperationsInProgress = (aStatus && aStatus != 'DONE' && aStatus != 'CANCELED' && aStatus != 'FAILED'); var queueOperationsInProgress = (aStatus && aStatus != 'DONE' && aStatus != 'CANCELED' && aStatus != 'FAILED');
@ -709,7 +715,7 @@ console.log("DROP"); //, anEvent);
return result; return result;
}, },
renderAttachmentStatus: function(aStatus, aServerStatus, aProgress) { renderAttachmentStatus: function (aStatus, aServerStatus, aProgress) {
var result; var result;
var status = aStatus ? aStatus : false; var status = aStatus ? aStatus : false;
@ -728,7 +734,7 @@ console.log("DROP"); //, anEvent);
result = React.DOM.span({'className': 'broken'}, "canceled"); result = React.DOM.span({'className': 'broken'}, "canceled");
break; break;
case 'DONE': case 'DONE':
result = React.DOM.span({'className': 'broken'}, "failed"); result = React.DOM.span({'className': 'done'}, "done");
break; break;
case false: case false:
result = React.DOM.span({'className': 'broken'}, "failed"); result = React.DOM.span({'className': 'broken'}, "failed");
@ -745,7 +751,7 @@ console.log("DROP"); //, anEvent);
return result; return result;
}, },
renderAttachmentActions: function(aStatus, aServerStatus, anAttachment) { renderAttachmentActions: function (aStatus, aServerStatus, anAttachment) {
var result; var result;
result = null; result = null;
@ -759,7 +765,7 @@ console.log("DROP"); //, anEvent);
return result; return result;
}, },
renderAttachment: function(anAttachment) { renderAttachment: function (anAttachment) {
var queueInfo = this.props['attachmentQueueInfo'].elementFetchCallback(anAttachment._reference) || []; var queueInfo = this.props['attachmentQueueInfo'].elementFetchCallback(anAttachment._reference) || [];
var queueStatus = queueInfo['status']; var queueStatus = queueInfo['status'];
var serverStatus = this.props['attachmentServerStatus'][anAttachment._reference]; var serverStatus = this.props['attachmentServerStatus'][anAttachment._reference];
@ -767,10 +773,6 @@ console.log("DROP"); //, anEvent);
var broken = (! serverStatus && ! queueOperationsInProgress && ! this.props['_isBrandNew']); var broken = (! serverStatus && ! queueOperationsInProgress && ! this.props['_isBrandNew']);
var status = this.renderAttachmentStatus(queueStatus, serverStatus, queueInfo['requestProgress']);
var actions = this.renderAttachmentActions(queueStatus, serverStatus, anAttachment['_attachment']);
var progressIndicator = this.renderAttachmentProgress(queueStatus, serverStatus, queueInfo['requestProgress']);;
return React.DOM.li({ return React.DOM.li({
'className': (broken) ? 'broken' : '', 'className': (broken) ? 'broken' : '',
'key': anAttachment._reference 'key': anAttachment._reference
@ -780,9 +782,9 @@ console.log("DROP"); //, anEvent);
React.DOM.span({'className': 'name'}, anAttachment.name), React.DOM.span({'className': 'name'}, anAttachment.name),
React.DOM.span({'className': 'size'}, filesize(anAttachment.size)), React.DOM.span({'className': 'size'}, filesize(anAttachment.size)),
]), ]),
React.DOM.span({'className': 'status'}, status), React.DOM.span({'className': 'status'}, this.renderAttachmentStatus (queueStatus, serverStatus, queueInfo['requestProgress'])),
React.DOM.span({'className': 'progress'}, progressIndicator), React.DOM.span({'className': 'progress'}, this.renderAttachmentProgress(queueStatus, serverStatus, queueInfo['requestProgress'])),
React.DOM.span({'className': 'actions'}, actions), React.DOM.span({'className': 'actions'}, this.renderAttachmentActions (queueStatus, serverStatus, anAttachment['_attachment'])),
]) ])
}, },
@ -798,7 +800,7 @@ console.log("DROP"); //, anEvent);
]), ]),
React.DOM.div({ React.DOM.div({
'className': 'cardUploadAttachments', 'className': 'cardUploadAttachments',
'onClick': MochiKit.Base.bind(function() { this.refs['attachmentInput'].getDOMNode().click() }, this), 'onClick': MochiKit.Base.bind(function() { this.refs['attachmentInput'].click() }, this),
'onDragOver': this.handleOnDragOver, 'onDragOver': this.handleOnDragOver,
'onDrop': this.handleOnDrop, 'onDrop': this.handleOnDrop,
},[ },[

View File

@ -28,6 +28,8 @@ Clipperz.PM.UI.Components.Cards.EditToolbarClass = React.createClass({
//============================================================================ //============================================================================
displayName: 'Clipperz.PM.UI.Components.Cards.EditToolbar',
propTypes: { propTypes: {
'hasPendingChanges': React.PropTypes.bool.isRequired, 'hasPendingChanges': React.PropTypes.bool.isRequired,
}, },

View File

@ -27,6 +27,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.Cards');
Clipperz.PM.UI.Components.Cards.FavIconClass = React.createClass({ Clipperz.PM.UI.Components.Cards.FavIconClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.Cards.FavIcon',
propTypes: { propTypes: {
'src': React.PropTypes.string, 'src': React.PropTypes.string,
}, },

View File

@ -28,6 +28,8 @@ Clipperz.PM.UI.Components.Cards.ListClass = React.createClass({
//========================================================================= //=========================================================================
displayName: 'Clipperz.PM.UI.Components.Cards.List',
propTypes: { propTypes: {
'cards': React.PropTypes.array, 'cards': React.PropTypes.array,
'featureSet': React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']).isRequired, 'featureSet': React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']).isRequired,
@ -45,7 +47,7 @@ Clipperz.PM.UI.Components.Cards.ListClass = React.createClass({
handleClick: function (anEvent) { handleClick: function (anEvent) {
if (this.isFeatureEnabled('CARD_DETAILS')) { if (this.isFeatureEnabled('CARD_DETAILS')) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectCard', {'reference':anEvent.currentTarget.dataset.reference, 'label':anEvent.currentTarget.dataset.label}, true); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectCard', {'cardInfo':{'reference':anEvent.currentTarget.dataset.reference, 'label':anEvent.currentTarget.dataset.label}, 'update':true});
} }
}, },
@ -63,7 +65,8 @@ Clipperz.PM.UI.Components.Cards.ListClass = React.createClass({
result = React.DOM.li({'className':Clipperz.PM.UI.Components.classNames(classes), 'onClick': this.handleClick, 'key':anItem['_reference'], 'data-reference':anItem['_reference'], 'data-label':anItem['label']}, [ result = React.DOM.li({'className':Clipperz.PM.UI.Components.classNames(classes), 'onClick': this.handleClick, 'key':anItem['_reference'], 'data-reference':anItem['_reference'], 'data-label':anItem['label']}, [
// React.DOM.span({'className':'favicon'}, Clipperz.PM.UI.Components.Cards.FavIcon({'src':anItem['favicon']})), // React.DOM.span({'className':'favicon'}, Clipperz.PM.UI.Components.Cards.FavIcon({'src':anItem['favicon']})),
React.DOM.span({'className':'label'}, anItem['label']), React.DOM.span({'className':'label'}, anItem['label']),
React.DOM.span({'className':'attachmentsCount'}, anItem['attachmentsCount'] ? 'attachment' : ''), anItem['hasBeenCertified'] != '' ? React.DOM.span({'className':'certificateStatus'}, 'certificate') : null,
anItem['attachmentsCount'] ? React.DOM.span({'className':'attachmentsCount'}, 'attachment') : null,
]); ]);
} }

View File

@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.Cards');
Clipperz.PM.UI.Components.Cards.PasswordGeneratorClass = React.createClass({ Clipperz.PM.UI.Components.Cards.PasswordGeneratorClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.Cards.PasswordGenerator',
charsetBlocks: { charsetBlocks: {
'chars_AZ': 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'chars_AZ': 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'chars_az': 'abcdefghijklmnopqrstuvwxyz', 'chars_az': 'abcdefghijklmnopqrstuvwxyz',

View File

@ -28,6 +28,8 @@ Clipperz.PM.UI.Components.Cards.TagEditorClass = React.createClass({
//============================================================================ //============================================================================
displayName: 'Clipperz.PM.UI.Components.Cards.TagEditor',
propTypes: { propTypes: {
'allTags': React.PropTypes.array, 'allTags': React.PropTypes.array,
'selectedTags': React.PropTypes.array.isRequired, 'selectedTags': React.PropTypes.array.isRequired,

View File

@ -28,6 +28,8 @@ Clipperz.PM.UI.Components.Cards.TextAreaClass = React.createClass({
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
displayName: 'Clipperz.PM.UI.Components.Cards.TextArea',
componentDidMount: function() { componentDidMount: function() {
this.recalculateSize(); this.recalculateSize();
this.getDOMNode().addEventListener('input', this.handleKeyDown, false); this.getDOMNode().addEventListener('input', this.handleKeyDown, false);

View File

@ -28,16 +28,39 @@ Clipperz.PM.UI.Components.Cards.ViewClass = React.createClass({
//============================================================================ //============================================================================
displayName: 'Clipperz.PM.UI.Components.Cards.View',
propTypes: { propTypes: {
'label': React.PropTypes.string /*.isRequired */ , 'label': React.PropTypes.string /*.isRequired */ ,
'loading': React.PropTypes.bool, 'loading': React.PropTypes.bool,
'proxyInfo': React.PropTypes.object.isRequired, // 'proxyInfo': React.PropTypes.object.isRequired,
}, },
getInitialState: function () { getInitialState: function () {
return {}; return {
// 'showCertificatePreview': false,
};
},
downloadCertificate: function (anEvent) {
if (this.isCertificatePublished()) {
// console.log("DOWNLOAD CERTIFICATE");
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'downloadCertificate', this.props['_reference']);
}
}, },
previewCertificate: function (anEvent) {
if (this.isCertificatePublished()) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showCertificatePreview', this.props['_reference']);
// this.setState({'showCertificatePreview':true});
}
},
hideCertificatePreview: function (anEvent) {
// this.setState({'showCertificatePreview':false});
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'hideCertificatePreview', this.props['_reference']);
},
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
handleDirectLoginClick: function (aDirectLogin) { handleDirectLoginClick: function (aDirectLogin) {
@ -163,6 +186,85 @@ Clipperz.PM.UI.Components.Cards.ViewClass = React.createClass({
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
hasCertificate: function () {
return ((typeof(this.props['certificateInfo']) != 'undefined') && (this.props['certificateInfo'] != null));
},
isCertificatePublished: function () {
return (this.props['certificateInfo'] && (this.props['certificateInfo']['status'] == 'published'));
},
//----------------------------------------------------------------------------
renderCertificatePreview: function () {
return React.DOM.div({'className':'certificatePreview'}, [
React.DOM.div({'className':'mask'}),
React.DOM.div({'className':'previewContent'}, [
React.DOM.header({}, [
React.DOM.span({'onClick': this.hideCertificatePreview}, "close")
]),
React.DOM.div({'className':'preview'}, Clipperz.PM.UI.Components.Cards.CertificateRenderer(this.props)),
React.DOM.footer({}, null)
])
]);
},
renderCertificateInfo: function (someCertificateInfo) {
var result;
if (this.hasCertificate()) {
var description;
var statusDescription;
var dateLabel;
var dateValue;
var transactionInfo;
var classes = {
'cardCertificateInfo': true,
'published': this.isCertificatePublished(),
'requested': !this.isCertificatePublished(),
};
if (this.isCertificatePublished()) {
description = "This card has been registered on the Bitcoin blockchain";
statusDescription = "confirmed";
dateLabel = "Registration date";
dateValue = (new XDate(someCertificateInfo['creationDate'])).toString("MMM d, yyyy - HH:mm");
transactionInfo = React.DOM.span({}, someCertificateInfo['txID']);
} else {
description = "This card will soon be registered on the Bitcoin blockchain";
statusDescription = "pending";
dateLabel = "Request date";
dateValue = (new XDate(someCertificateInfo['requestDate'])).toString("MMM d, yyyy - HH:mm");
transactionInfo = React.DOM.span({}, "N.A.");
}
result = React.DOM.div({'className': Clipperz.PM.UI.Components.classNames(classes)}, [
React.DOM.div({}, [
React.DOM.h3({}, "certificate"),
React.DOM.p({}, description),
]),
React.DOM.div({'className':'info'}, [
React.DOM.div({'className':'details'}, [
React.DOM.dl({}, [ React.DOM.dt({}, dateLabel), React.DOM.dd({}, dateValue) ]),
React.DOM.dl({}, [ React.DOM.dt({}, 'transaction'), React.DOM.dd({'className':'transactionInfo'}, transactionInfo) ]),
React.DOM.dl({}, [ React.DOM.dt({}, 'status'), React.DOM.dd({}, statusDescription) ]),
]),
React.DOM.div({'className':'links'}, [
React.DOM.a({'className':'certificate', 'onClick':this.downloadCertificate}, "certificate"),
React.DOM.a({'className':'preview', 'onClick':this.previewCertificate}, "preview"),
]),
]),
])
} else {
result = null;
}
return result;
},
//----------------------------------------------------------------------------
renderLabel: function (aLabel) { renderLabel: function (aLabel) {
return React.DOM.h3({'className':'cardLabel'}, aLabel); return React.DOM.h3({'className':'cardLabel'}, aLabel);
}, },
@ -292,7 +394,7 @@ Clipperz.PM.UI.Components.Cards.ViewClass = React.createClass({
var queueOperationsInProgress = (status && (status != 'DONE' && status != 'CANCELED' && status != 'FAILED')); var queueOperationsInProgress = (status && (status != 'DONE' && status != 'CANCELED' && status != 'FAILED'));
result = null; result = null;
if (status == 'FAILED') { if (status == 'FAILED') {
result = React.DOM.span({'className': 'failed'}, "failed"); result = React.DOM.span({'className': 'failed'}, "failed");
} else if (status == 'UPLOADING' || status == 'DOWNLOADING') { } else if (status == 'UPLOADING' || status == 'DOWNLOADING') {
@ -304,7 +406,7 @@ Clipperz.PM.UI.Components.Cards.ViewClass = React.createClass({
result = React.DOM.span({'className': 'broken'}, "canceled"); result = React.DOM.span({'className': 'broken'}, "canceled");
break; break;
case 'DONE': case 'DONE':
result = React.DOM.span({'className': 'broken'}, "failed"); result = React.DOM.span({'className': 'done'}, "done");
break; break;
case false: case false:
result = React.DOM.span({'className': 'broken'}, "failed"); result = React.DOM.span({'className': 'broken'}, "failed");
@ -320,6 +422,7 @@ Clipperz.PM.UI.Components.Cards.ViewClass = React.createClass({
return result; return result;
}, },
renderAttachmentActions: function(aStatus, aServerStatus, anAttachment) { renderAttachmentActions: function(aStatus, aServerStatus, anAttachment) {
var result; var result;
@ -401,20 +504,25 @@ Clipperz.PM.UI.Components.Cards.ViewClass = React.createClass({
renderCard: function () { renderCard: function () {
var classes = { var classes = {
'view': true, 'view': true,
'archived': this.props['_isArchived'] 'archived': this.props['_isArchived'],
'registered': this.hasCertificate()
} }
return React.DOM.div({'className':Clipperz.PM.UI.Components.classNames(classes)},[ return React.DOM.div({'className':Clipperz.PM.UI.Components.classNames(classes)},[
Clipperz.PM.UI.Components.Cards.CommandToolbar(this.props), Clipperz.PM.UI.Components.Cards.CommandToolbar(this.props),
React.DOM.div({'className':'content'}, [ React.DOM.div({'className':'content'}, [
this.renderCertificateInfo(this.props['certificateInfo']),
this.renderLabel(this.props['label']), this.renderLabel(this.props['label']),
//React.DOM.div({}, "ID:" + this.props['ID']),
//React.DOM.div({}, "Reference:" + this.props['_reference']),
this.renderTags(this.props['tags']), this.renderTags(this.props['tags']),
this.renderFields(this.props['fields']), this.renderFields(this.props['fields']),
this.renderAttachments(MochiKit.Base.values(this.props['attachments'])), this.renderAttachments(MochiKit.Base.values(this.props['attachments'])),
this.renderNotes(this.props['notes']), this.renderNotes(this.props['notes']),
this.renderDirectLogins(this.props['directLogins']), this.renderDirectLogins(this.props['directLogins']),
]), ]),
this.props['ask'] ? Clipperz.PM.UI.Components.DialogBox(this.props['ask']) : null this.props['ask'] ? Clipperz.PM.UI.Components.DialogBox(this.props['ask']) : null,
this.props['showCertificatePreview'] ? this.renderCertificatePreview() : null
]); ]);
}, },
@ -422,7 +530,7 @@ Clipperz.PM.UI.Components.Cards.ViewClass = React.createClass({
render: function () { render: function () {
var result; var result;
//console.log("VIEW", this.props);
if (this.props['loading'] == true) { if (this.props['loading'] == true) {
result = this.renderLoading(); result = this.renderLoading();
} else if (this.props['_reference']) { } else if (this.props['_reference']) {

View File

@ -0,0 +1,82 @@
/*
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');
Clipperz.PM.UI.Components.CertificateQueueBoxClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.CertificateQueueBox',
propTypes: {
'certificateQueueInfo': React.PropTypes.object.isRequired,
'certificateQueueBoxStatus': React.PropTypes.string.isRequired,
},
acknowledgeCertificate: function (aRecordReference) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'closeCertificateNotification', aRecordReference);
},
showCertificateCard: function (aRecordReference) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'showCertificateCard', aRecordReference);
},
renderCertificateInfo: function (aCertificateInfo) {
var result;
if (aCertificateInfo['status'] != 'acknowledged') {
result = React.DOM.li({'className':aCertificateInfo['status']}, [
React.DOM.span({'className':'icon'}, "certificate"),
React.DOM.span({'className':'name', 'onClick':MochiKit.Base.method(this, 'showCertificateCard', aCertificateInfo['reference'])}, aCertificateInfo['label']),
React.DOM.span({'className':'status'}, [
React.DOM.span({'className':'statusString'}, aCertificateInfo['status'] == 'requested' ? 'pending' : 'registered')
]),
React.DOM.span({'className':'close'}, [
React.DOM.a({'className':'close', 'onClick':MochiKit.Base.method(this, 'acknowledgeCertificate', aCertificateInfo['reference'])}, "remove field")
])
]);
} else {
result = null;
}
return result;
},
render: function () {
var certificatesInfo;
certificatesInfo = this.props['certificateQueueInfo'] ? MochiKit.Base.map(MochiKit.Base.method(this, 'renderCertificateInfo'), this.props['certificateQueueInfo']) : [];
certificatesInfo = MochiKit.Base.filter(function (aValue) { return aValue != null; }, certificatesInfo);
return React.DOM.div({
'className': 'certificateQueueStatus ' + this.props['certificateQueueBoxStatus'],
}, [
React.DOM.div({'className': 'arrow'}),
React.DOM.ul({'className':'certificateInfos'}, (certificatesInfo.length > 0) ? certificatesInfo : React.DOM.p({}, "No certificates pending")),
]);
}
//=========================================================================
});
Clipperz.PM.UI.Components.CertificateQueueBox = React.createFactory(Clipperz.PM.UI.Components.CertificateQueueBoxClass);

View File

@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components');
Clipperz.PM.UI.Components.CheckboxClass = React.createClass({ Clipperz.PM.UI.Components.CheckboxClass = React.createClass({
// http://development.tobypitman.com/iphoneCheckboxes/iphoneCheckboxes2.html // http://development.tobypitman.com/iphoneCheckboxes/iphoneCheckboxes2.html
displayName: 'Clipperz.PM.UI.Components.Checkbox',
propTypes: { propTypes: {
'checked': React.PropTypes.bool.isRequired, 'checked': React.PropTypes.bool.isRequired,
'id': React.PropTypes.string.isRequired, 'id': React.PropTypes.string.isRequired,

View File

@ -25,6 +25,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components');
Clipperz.PM.UI.Components.DialogBoxClass = React.createClass({ Clipperz.PM.UI.Components.DialogBoxClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.DialogBox',
propTypes: { propTypes: {
'info': React.PropTypes.object.isRequired, 'info': React.PropTypes.object.isRequired,
'deferred': React.PropTypes.object.isRequired 'deferred': React.PropTypes.object.isRequired
@ -54,19 +56,28 @@ console.log("DIALOG BOX - key UP", anEvent);
var answerInfo = this.props['info']['possibleAnswers'][anAnswerInfoKey]; var answerInfo = this.props['info']['possibleAnswers'][anAnswerInfoKey];
var classes = { var classes = {
'button': true, 'button': true,
'isDefault': answerInfo['isDefault'] 'isDefault': answerInfo['isDefault'],
'disabled': answerInfo['disabled']
}; };
return React.DOM.div({'className':Clipperz.PM.UI.Components.classNames(classes), 'onClick':this.handleAnswerButton, 'data-answer-key':anAnswerInfoKey}, answerInfo['label']) return React.DOM.div({
'className':Clipperz.PM.UI.Components.classNames(classes),
'onClick':this.handleAnswerButton,
'data-answer-key':anAnswerInfoKey
}, answerInfo['label']);
}, },
//========================================================================= //=========================================================================
render: function () { render: function () {
//console.log("DIALOG BOX", this.props);
return React.DOM.div({'className':'dialogBox' /*, 'onKeyDown':this.handleKeyDown, 'onKeyPress':this.handleKeyPress, 'onKeyUp':this.handleKeyUp */ }, [ return React.DOM.div({'className':'dialogBox' /*, 'onKeyDown':this.handleKeyDown, 'onKeyPress':this.handleKeyPress, 'onKeyUp':this.handleKeyUp */ }, [
React.DOM.div({'className':'mask'}), React.DOM.div({'className':'mask'}),
React.DOM.div({'className':'dialog'}, [ React.DOM.div({'className':'dialog'}, [
React.DOM.h3({'className': 'message'}, this.props['info']['question']), React.DOM.h3({'className': 'message'}, this.props['info']['question']),
this.props['info']['description']
? React.DOM.div({'className':'description'}, this.props['info']['description'])
: null,
React.DOM.div({'className': 'answers'}, MochiKit.Base.map(this.renderAnswerButton, MochiKit.Base.keys(this.props['info']['possibleAnswers']))) React.DOM.div({'className': 'answers'}, MochiKit.Base.map(this.renderAnswerButton, MochiKit.Base.keys(this.props['info']['possibleAnswers'])))
]) ])
]); ]);

View File

@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components');
Clipperz.PM.UI.Components.DocumentEncryptionSandboxClass = React.createClass({ Clipperz.PM.UI.Components.DocumentEncryptionSandboxClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.DocumentEncryptionSandbox',
getInitialState: function() { getInitialState: function() {
return { return {
'documentMeta': null, 'documentMeta': null,

View File

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

View File

@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures');
Clipperz.PM.UI.Components.ExtraFeatures.DataExportClass = React.createClass({ Clipperz.PM.UI.Components.ExtraFeatures.DataExportClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataExport',
propTypes: { propTypes: {
// featureSet: React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']).isRequired, // featureSet: React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']).isRequired,
// 'level': React.PropTypes.oneOf(['hide', 'info', 'warning', 'error']).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.Base.module('Clipperz.PM.UI.Components.ExtraFeatures');
Clipperz.PM.UI.Components.ExtraFeatures.DataImportClass = React.createClass({ Clipperz.PM.UI.Components.ExtraFeatures.DataImportClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport',
getInitialState: function() { getInitialState: function() {
return { return {
'importContext': new Clipperz.PM.UI.ImportContext(this), '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.Base.module('Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV');
Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.ColumnsClass = React.createClass({ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.ColumnsClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.Columns',
getInitialState: function() { getInitialState: function() {
return { 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({ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.HiddenClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.Hidden',
getInitialState: function() { getInitialState: function() {
return { return {
'hiddenFields': this.props.importContext.state('csvData.hiddenFields'), '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({ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.LabelsClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.Labels',
getInitialState: function() { getInitialState: function() {
return { return {
'useFirstRowAsLabels': this.props.importContext.state('csvData.useFirstRowAsLabels'), 'useFirstRowAsLabels': this.props.importContext.state('csvData.useFirstRowAsLabels'),
@ -57,7 +59,7 @@ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.LabelsClass = React.creat
var newState; var newState;
newState = this.state; 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.setState(newState);
this.updateImportContextState(); 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.Base.module('Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV');
Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.NotesClass = React.createClass({ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.NotesClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.Notes',
getInitialState: function() { getInitialState: function() {
return { return {
'notesIndex': this.props.importContext.state('csvData.notesIndex'), '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({ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.TitlesClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.CSV.Titles',
getInitialState: function() { getInitialState: function() {
return { return {
'titleIndex': this.props.importContext.state('csvData.titleIndex'), '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({ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.ImportClass = React.createClass({
//========================================================================= //=========================================================================
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.Import',
importHandler: function (anEvent) { importHandler: function (anEvent) {
var recordsToImport = this.props.importContext.state('recordsToImport'); 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({ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.InputClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.Input',
getInitialState: function() { getInitialState: function() {
return { return {
'inputString': this.props.importContext.inputString(), 'inputString': this.props.importContext.inputString(),
@ -46,7 +48,7 @@ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.InputClass = React.createClas
var jsonData; var jsonData;
var parsedInput; var parsedInput;
var inputString = this.refs['input-textarea'].getDOMNode().value.trim(); var inputString = this.refs['input-textarea'].value.trim();
// this.props.importContext.setData(inputString); // this.props.importContext.setData(inputString);
result = {'inputString': inputString}; result = {'inputString': inputString};
@ -80,7 +82,7 @@ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.InputClass = React.createClas
var re = new RegExp('.*<textarea>(.*)<\/textarea>.*','g'); var re = new RegExp('.*<textarea>(.*)<\/textarea>.*','g');
if (re.test(someHtml)) { if (re.test(someHtml)) {
textarea = this.refs['input-textarea'].getDOMNode(); textarea = this.refs['input-textarea'];
textarea.innerHTML = someHtml.replace(re, '$1'); textarea.innerHTML = someHtml.replace(re, '$1');
result = textarea.innerHTML; result = textarea.innerHTML;
} else { } 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 // 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 // https://code.google.com/p/chromium/issues/detail?id=168387
// http://www.quirksmode.org/blog/archives/2009/09/the_html5_drag.html // http://www.quirksmode.org/blog/archives/2009/09/the_html5_drag.html
anEvent.stopPropagation();
anEvent.preventDefault(); anEvent.preventDefault();
anEvent.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
}, },
handleTextareaChange: function () { handleTextareaChange: function () {
// var newInputString; // var newInputString;
// //
// newInputString = this.refs['input-textarea'].getDOMNode().value; // newInputString = this.refs['input-textarea'].value;
// this.setState({'inputString': newInputString}); // this.setState({'inputString': newInputString});
// this.props.importContext.setInputString(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.br({}),
React.DOM.a({ React.DOM.a({
'className': 'button', '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") }, "select it manually")
]), ]),
React.DOM.div({'className': 'description'}, 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({ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.PreviewClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DataImport.Preview',
getInitialState: function() { getInitialState: function() {
var recordsToImport; var recordsToImport;
@ -83,7 +85,7 @@ Clipperz.PM.UI.Components.ExtraFeatures.DataImport.PreviewClass = React.createCl
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
handleImportTagTextChange: function() { handleImportTagTextChange: function() {
var newTag = this.refs['importTagText'].getDOMNode().value; var newTag = this.refs['importTagText'].value;
this.props.importContext.setState('importTag', newTag); 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({ Clipperz.PM.UI.Components.ExtraFeatures.DeleteAccountClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DeleteAccount',
propTypes: { propTypes: {
// featureSet: React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']).isRequired, // featureSet: React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']).isRequired,
// 'level': React.PropTypes.oneOf(['hide', 'info', 'warning', 'error']).isRequired // 'level': React.PropTypes.oneOf(['hide', 'info', 'warning', 'error']).isRequired
@ -50,15 +52,15 @@ Clipperz.PM.UI.Components.ExtraFeatures.DeleteAccountClass = React.createClass({
var deferredResult; var deferredResult;
deferredResult = new Clipperz.Async.Deferred("DeleteAccount.handleDeleteAccount", {trace: false}); 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){ deferredResult.addMethod(this, function(passCheck){
var username = this.refs['username'].getDOMNode().value; var username = this.refs['username'].value;
var passphrase = this.refs['passphrase'].getDOMNode().value; var passphrase = this.refs['passphrase'].value;
this.setState({ this.setState({
'username': (username != '') ? (username == this.props.userInfo['username']) ? 'valid' : 'invalid' : 'empty', 'username': (username != '') ? (username == this.props.userInfo['username']) ? 'valid' : 'invalid' : 'empty',
'passphrase': (passphrase != '') ? (passCheck) ? '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.input({'key':'passphrase', 'className': this.state['passphrase'], 'type':'password', 'name':'passphrase', 'ref':'passphrase', 'placeholder':"passphrase"}),
React.DOM.p({}, [ React.DOM.p({}, [
React.DOM.input({'key':'confirm', 'className':'confirmCheckbox', 'type':'checkbox', 'id':'deleteAccountConfirmCheckbox', 'name':'confirm', 'ref':'confirm'}), 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") 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({ Clipperz.PM.UI.Components.ExtraFeatures.DevicePINClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.DevicePIN',
propTypes: { propTypes: {
// featureSet: React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']).isRequired, // featureSet: React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']).isRequired,
// 'level': React.PropTypes.oneOf(['hide', 'info', 'warning', 'error']).isRequired // 'level': React.PropTypes.oneOf(['hide', 'info', 'warning', 'error']).isRequired
@ -59,7 +61,7 @@ Clipperz.PM.UI.Components.ExtraFeatures.DevicePINClass = React.createClass({
}, },
setFocus: function() { setFocus: function() {
this.refs['pinValue'].getDOMNode().focus(); this.refs['pinValue'].focus();
}, },
resetPIN: function() { resetPIN: function() {

View File

@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures');
Clipperz.PM.UI.Components.ExtraFeatures.OTPClass = React.createClass({ Clipperz.PM.UI.Components.ExtraFeatures.OTPClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.OTP',
getInitialState: function() { getInitialState: function() {
return { return {
// 'selectedOTPs': [], // 'selectedOTPs': [],
@ -82,7 +84,7 @@ Clipperz.PM.UI.Components.ExtraFeatures.OTPClass = React.createClass({
}, },
handleLabelSave: function (anOTP) { 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() this.handleLabelCancel()
}, },

View File

@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.ExtraFeatures');
Clipperz.PM.UI.Components.ExtraFeatures.PassphraseClass = React.createClass({ Clipperz.PM.UI.Components.ExtraFeatures.PassphraseClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.Passphrase',
propTypes: { propTypes: {
}, },
@ -44,18 +46,18 @@ Clipperz.PM.UI.Components.ExtraFeatures.PassphraseClass = React.createClass({
resetForm: function () { resetForm: function () {
this.setState(this.getInitialState()); this.setState(this.getInitialState());
this.refs['username'].getDOMNode().value = ''; this.refs['username'].value = '';
this.refs['old-passphrase'].getDOMNode().value = ''; this.refs['old-passphrase'].value = '';
this.refs['new-passphrase'].getDOMNode().value = ''; this.refs['new-passphrase'].value = '';
this.refs['confirm-new-passphrase'].getDOMNode().value = ''; this.refs['confirm-new-passphrase'].value = '';
this.refs['confirm'].getDOMNode().checked = false; this.refs['confirm'].checked = false;
}, },
handleChangePassphrase: function(event) { handleChangePassphrase: function(event) {
var newPassphrase; var newPassphrase;
event.preventDefault(); event.preventDefault();
newPassphrase = this.refs['new-passphrase'].getDOMNode().value; newPassphrase = this.refs['new-passphrase'].value;
this.resetForm(); this.resetForm();
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'changePassphrase', newPassphrase); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'changePassphrase', newPassphrase);
@ -65,19 +67,19 @@ Clipperz.PM.UI.Components.ExtraFeatures.PassphraseClass = React.createClass({
var deferredResult; var deferredResult;
deferredResult = new Clipperz.Async.Deferred("Passphrase.handleFormChange", {trace: false}); 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){ deferredResult.addMethod(this, function(passCheck){
var username = this.refs['username'].getDOMNode().value; var username = this.refs['username'].value;
var oldPassphrase = this.refs['old-passphrase'].getDOMNode().value; var oldPassphrase = this.refs['old-passphrase'].value;
var newPassphrase = this.refs['new-passphrase'].getDOMNode().value; var newPassphrase = this.refs['new-passphrase'].value;
var confirmNewPassphrase = this.refs['confirm-new-passphrase'].getDOMNode().value; var confirmNewPassphrase = this.refs['confirm-new-passphrase'].value;
this.setState({ this.setState({
'username': (username != '') ? [(username == this.props.userInfo['username']) ? 'valid' : 'invalid'] : 'empty', 'username': (username != '') ? [(username == this.props.userInfo['username']) ? 'valid' : 'invalid'] : 'empty',
'old-passphrase': (oldPassphrase != '') ? [(passCheck) ? 'valid' : 'invalid'] : 'empty', 'old-passphrase': (oldPassphrase != '') ? [(passCheck) ? 'valid' : 'invalid'] : 'empty',
'new-passphrase': (newPassphrase != '') ? 'valid' : 'empty', 'new-passphrase': (newPassphrase != '') ? 'valid' : 'empty',
'confirm-new-passphrase': (confirmNewPassphrase != '') ? [(confirmNewPassphrase == newPassphrase) ? 'valid' : 'invalid'] : '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({ Clipperz.PM.UI.Components.ExtraFeatures.PreferencesClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.ExtraFeatures.Preferences',
getInitialState: function() { getInitialState: function() {
return { return {
'editedPreferences': new Clipperz.KeyValueObjectStore() 'editedPreferences': new Clipperz.KeyValueObjectStore()
@ -66,7 +68,7 @@ Clipperz.PM.UI.Components.ExtraFeatures.PreferencesClass = React.createClass({
checkboxClick: function (aRef) { checkboxClick: function (aRef) {
return MochiKit.Base.bind(function (anEvent) { return MochiKit.Base.bind(function (anEvent) {
// console.log("CHECKBOX CLICK", this, this.refs, this.refs[aRef]); // console.log("CHECKBOX CLICK", this, this.refs, this.refs[aRef]);
this.refs[aRef].getDOMNode().click(); this.refs[aRef].click();
}, this); }, this);
}, },

View File

@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components');
Clipperz.PM.UI.Components.HelpClass = React.createClass({ Clipperz.PM.UI.Components.HelpClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.Help',
close: function (anEvent) { close: function (anEvent) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'closeHelp'); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'closeHelp');
}, },

View File

@ -25,6 +25,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components');
Clipperz.PM.UI.Components.MessageBoxClass = React.createClass({ Clipperz.PM.UI.Components.MessageBoxClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.MessageBox',
propTypes: { propTypes: {
'level': React.PropTypes.oneOf(['HIDE', 'INFO', 'WARNING', 'ERROR']).isRequired, 'level': React.PropTypes.oneOf(['HIDE', 'INFO', 'WARNING', 'ERROR']).isRequired,
'message': React.PropTypes.string.isRequired 'message': React.PropTypes.string.isRequired

View File

@ -24,33 +24,13 @@ refer to http://www.clipperz.com.
Clipperz.Base.module('Clipperz.PM.UI.Components.Pages'); Clipperz.Base.module('Clipperz.PM.UI.Components.Pages');
Clipperz.PM.UI.Components.Pages.CardDetailPageClass = React.createClass({ Clipperz.PM.UI.Components.Pages.CardDetailPageClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.Pages.CardDetailPage',
propTypes: { propTypes: {
'allTags': React.PropTypes.array, 'allTags': React.PropTypes.array,
}, },
/*
viewComponentProps: function () {
var result;
result = this.props['selectedCard'];
if (result) {
result['style'] = this.props['style'];
}
return result;
},
render: function () {
var result;
if (this.props['mode'] == 'edit') {
result = Clipperz.PM.UI.Components.Cards.Edit(this.viewComponentProps());
} else {
result = Clipperz.PM.UI.Components.Cards.View(this.viewComponentProps());
}
return result;
},
*/
render: function () { render: function () {
return Clipperz.PM.UI.Components.Cards.Detail(this.props); return Clipperz.PM.UI.Components.Cards.Detail(this.props);
} }

View File

@ -25,26 +25,28 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.Pages');
Clipperz.PM.UI.Components.Pages.ErrorPageClass = React.createClass({ Clipperz.PM.UI.Components.Pages.ErrorPageClass = React.createClass({
getDefaultProps: function () { displayName: 'Clipperz.PM.UI.Components.Pages.ErrorPage',
return {
// template: Clipperz.PM.UI.Components.PageTemplate
}
},
'propTypes': {
// type: React.PropTypes.oneOf(['PERMANENT', 'TEMPORARY']),
message: React.PropTypes.string.isRequired,
template: React.PropTypes.func
},
render: function () { render: function () {
return React.DOM.div({className:'error-message'}, this.props.message); //console.log("ERROR PAGE", this.props);
}, return React.DOM.div({}, [
React.DOM.header({}, [
// render: function () { React.DOM.h2({}, 'clipperz')
// return new this.props.template({'innerComponent': this._render()}); ]),
// } React.DOM.div({}, [
React.DOM.div({'className':'error-box'}, [
React.DOM.div({}, [
React.DOM.p({}, "Ops!"),
React.DOM.p({}, "Sorry, something went wrong."),
React.DOM.p({}, "Please reload."),
]),
React.DOM.div({'className':'error-message'}, [
React.DOM.p({}, this.props['error'] ? this.props['error']['message'] : '')
])
])
])
])
}
}); });
Clipperz.PM.UI.Components.Pages.ErrorPage = React.createFactory(Clipperz.PM.UI.Components.Pages.ErrorPageClass); Clipperz.PM.UI.Components.Pages.ErrorPage = React.createFactory(Clipperz.PM.UI.Components.Pages.ErrorPageClass);

View File

@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.Pages');
Clipperz.PM.UI.Components.Pages.LoginPageClass = React.createClass({ Clipperz.PM.UI.Components.Pages.LoginPageClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.Pages.LoginPage',
propTypes: { propTypes: {
mode: React.PropTypes.oneOf(['CREDENTIALS','PIN']).isRequired, mode: React.PropTypes.oneOf(['CREDENTIALS','PIN']).isRequired,
isNewUserRegistrationAvailable: React.PropTypes.bool.isRequired, isNewUserRegistrationAvailable: React.PropTypes.bool.isRequired,
@ -59,7 +61,7 @@ Clipperz.PM.UI.Components.Pages.LoginPageClass = React.createClass({
handleChange: function (anEvent) { handleChange: function (anEvent) {
var refs = this.refs; var refs = this.refs;
var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName].getDOMNode() == anEvent.target}, MochiKit.Base.keys(this.refs))[0]; var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName] == anEvent.target}, MochiKit.Base.keys(this.refs))[0];
var newState = {}; var newState = {};
newState[refName] = anEvent.target.value; newState[refName] = anEvent.target.value;
@ -70,8 +72,8 @@ Clipperz.PM.UI.Components.Pages.LoginPageClass = React.createClass({
if (this.mode() == 'CREDENTIALS') { if (this.mode() == 'CREDENTIALS') {
var newState; var newState;
var usernameValue = this.refs['username'].getDOMNode().value; var usernameValue = this.refs['username'].value;
var passphraseValue = this.refs['passphrase'].getDOMNode().value; var passphraseValue = this.refs['passphrase'].value;
newState = {}; newState = {};
@ -87,11 +89,11 @@ Clipperz.PM.UI.Components.Pages.LoginPageClass = React.createClass({
handleCredentialSubmit: function (event) { handleCredentialSubmit: function (event) {
event.preventDefault(); event.preventDefault();
this.refs['passphrase'].getDOMNode().blur(); this.refs['passphrase'].blur();
var credentials = { var credentials = {
'username': this.refs['username'].getDOMNode().value, 'username': this.refs['username'].value,
'passphrase': this.refs['passphrase'].getDOMNode().value 'passphrase': this.refs['passphrase'].value
} }
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', credentials); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', credentials);
}, },
@ -116,7 +118,7 @@ Clipperz.PM.UI.Components.Pages.LoginPageClass = React.createClass({
}, },
loginForm: function () { loginForm: function () {
return React.DOM.form({'key':'form', 'className':'loginForm credentials', 'autoComplete':'off', 'autoCorrect':'off', 'autoCapitalize':'off', 'onChange':this.handleChange, 'onSubmit':this.handleCredentialSubmit}, [ return React.DOM.form({'key':'loginForm', 'className':'loginForm credentials', 'autoComplete':'off', 'autoCorrect':'off', 'autoCapitalize':'off', 'onChange':this.handleChange, 'onSubmit':this.handleCredentialSubmit}, [
React.DOM.div({'key':'fields'},[ React.DOM.div({'key':'fields'},[
React.DOM.label({'key':'username-label', 'htmlFor' :'name'}, "username"), React.DOM.label({'key':'username-label', 'htmlFor' :'name'}, "username"),
React.DOM.input({'key':'username', 'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'autoComplete':'off', 'autoCorrect':'off', 'autoCapitalize':'off', 'spellCheck': false}), React.DOM.input({'key':'username', 'type':'text', 'name':'name', 'ref':'username', 'placeholder':"username", 'autoComplete':'off', 'autoCorrect':'off', 'autoCapitalize':'off', 'spellCheck': false}),
@ -128,10 +130,10 @@ Clipperz.PM.UI.Components.Pages.LoginPageClass = React.createClass({
}, },
submitPIN: function (event) { submitPIN: function (event) {
this.refs['pin'].getDOMNode().blur(); this.refs['pin'].blur();
var credentials = { var credentials = {
pin: this.refs['pin'].getDOMNode().value pin: this.refs['pin'].value
} }
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', credentials); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'doLogin', credentials);
@ -153,7 +155,7 @@ Clipperz.PM.UI.Components.Pages.LoginPageClass = React.createClass({
// handlePinFocus: function(anEvent) { // handlePinFocus: function(anEvent) {
// // anEvent.preventDefault(); // // anEvent.preventDefault();
// this.refs['pin'].getDOMNode().focus(); // this.refs['pin'].focus();
// }, // },
// pinFormDigits: function() { // pinFormDigits: function() {
@ -179,12 +181,13 @@ Clipperz.PM.UI.Components.Pages.LoginPageClass = React.createClass({
pinForm: function () { pinForm: function () {
return React.DOM.form({ return React.DOM.form({
'key':'pinForm',
'className':'pinForm pin', 'className':'pinForm pin',
'autoComplete':'off', 'autoComplete':'off',
'onSubmit': function(anEvent) {anEvent.preventDefault();}, 'onSubmit': function(anEvent) {anEvent.preventDefault();},
}, [ }, [
React.DOM.div({'key':'pinFormDiv'},[ React.DOM.div({'key':'pinFormDiv'},[
React.DOM.label({'htmlFor':'pin'}, "Enter your PIN"), React.DOM.label({'key':'pinLabel', 'htmlFor':'pin'}, "Enter your PIN"),
React.DOM.input({ React.DOM.input({
'type':'tel', 'type':'tel',
'name':'pin', 'name':'pin',
@ -199,6 +202,7 @@ Clipperz.PM.UI.Components.Pages.LoginPageClass = React.createClass({
}), }),
// React.DOM.div({'className': 'pinContainer'}, this.pinFormDigits()), // React.DOM.div({'className': 'pinContainer'}, this.pinFormDigits()),
React.DOM.a({ React.DOM.a({
'key':'pinAnchor',
'className': 'passphraseLogin', 'className': 'passphraseLogin',
'onClick': this.forcePassphraseLogin, 'onClick': this.forcePassphraseLogin,
}, "Login with passphrase") }, "Login with passphrase")
@ -212,12 +216,12 @@ Clipperz.PM.UI.Components.Pages.LoginPageClass = React.createClass({
this.setState({ this.setState({
'pin': '' 'pin': ''
}) })
this.refs['pin'].getDOMNode().focus(); this.refs['pin'].focus();
} else { } else {
if (this.refs['username'].getDOMNode().value == '') { if (this.refs['username'].value == '') {
this.refs['username'].getDOMNode().focus(); this.refs['username'].focus();
} else{ } else{
this.refs['passphrase'].getDOMNode().select(); this.refs['passphrase'].select();
} }
} }
}, },
@ -234,22 +238,22 @@ Clipperz.PM.UI.Components.Pages.LoginPageClass = React.createClass({
return React.DOM.div({'key':'loginForm', 'className':'loginForm content ' + this.props['style']}, [ return React.DOM.div({'key':'loginForm', 'className':'loginForm content ' + this.props['style']}, [
Clipperz.PM.UI.Components.AccountStatus(MochiKit.Base.update(this.props['proxyInfo'])), Clipperz.PM.UI.Components.AccountStatus(MochiKit.Base.update(this.props['proxyInfo'])),
React.DOM.header({'key':'header'}, [ React.DOM.header({'key':'header'}, [
React.DOM.div({'className':'headerContent'}, [ React.DOM.div({'key':'div', 'className':'headerContent'}, [
React.DOM.h3({}, 'clipperz'), React.DOM.h3({'key':'h3'}, 'clipperz'),
React.DOM.h5({}, 'keep it to yourself'), React.DOM.h5({'key':'h5'}, 'keep it to yourself'),
]), ]),
]), ]),
React.DOM.div({'key':'formWrapper', 'className':'form body'}, [ React.DOM.div({'key':'formWrapper', 'className':'form body'}, [
React.DOM.div({'className':'bodyContent'}, [ React.DOM.div({'key':'div', 'className':'bodyContent'}, [
this.mode() == 'PIN' ? this.pinForm() : this.loginForm(), this.mode() == 'PIN' ? this.pinForm() : this.loginForm(),
this.props['isNewUserRegistrationAvailable'] ? registrationLink : null, this.props['isNewUserRegistrationAvailable'] ? registrationLink : null,
]), ]),
]), ]),
React.DOM.div({'key':'afterBody', 'className':'afterBody'}), React.DOM.div({'key':'afterBody', 'className':'afterBody'}),
React.DOM.div({'className':'other', 'key':'other'}, [ React.DOM.div({'key':'other', 'className':'other'}, [
React.DOM.div({'className':'otherContent'}, [ React.DOM.div({'key':'otherContent', 'className':'otherContent'}, [
React.DOM.div({'key':'links', 'className':'links'}, [ React.DOM.div({'key':'links', 'className':'links'}, [
React.DOM.ul({}, [ React.DOM.ul({'key':'ul'}, [
React.DOM.li({'key':'about', 'onClick':this.showUrl('/about/')}, "About"), React.DOM.li({'key':'about', 'onClick':this.showUrl('/about/')}, "About"),
React.DOM.li({'key':'terms', 'onClick':this.showUrl('/terms_service/')}, "Terms of service"), React.DOM.li({'key':'terms', 'onClick':this.showUrl('/terms_service/')}, "Terms of service"),
React.DOM.li({'key':'privacy', 'onClick':this.showUrl('/privacy_policy/')}, "Privacy"), React.DOM.li({'key':'privacy', 'onClick':this.showUrl('/privacy_policy/')}, "Privacy"),
@ -258,7 +262,7 @@ Clipperz.PM.UI.Components.Pages.LoginPageClass = React.createClass({
]) ])
]), ]),
React.DOM.footer({'key':'footer'}, [ React.DOM.footer({'key':'footer'}, [
React.DOM.div({'className':'footerContent'}, [ React.DOM.div({'key':'div', 'className':'footerContent'}, [
React.DOM.div({'key':'applicationVersion', 'className':'applicationVersion'}, [ React.DOM.div({'key':'applicationVersion', 'className':'applicationVersion'}, [
React.DOM.span({'key':'applicationVersionLabel'}, "application version"), React.DOM.span({'key':'applicationVersionLabel'}, "application version"),
React.DOM.a({'key':'applicationVersionLink', 'href':'https://github.com/clipperz/password-manager/commit/' + Clipperz_version, 'target':'github'}, Clipperz_version) React.DOM.a({'key':'applicationVersionLink', 'href':'https://github.com/clipperz/password-manager/commit/' + Clipperz_version, 'target':'github'}, Clipperz_version)

View File

@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.Pages');
Clipperz.PM.UI.Components.Pages.MainPageClass = React.createClass({ Clipperz.PM.UI.Components.Pages.MainPageClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.Pages.MainPage',
getDefaultProps: function () { getDefaultProps: function () {
return { return {
featureSet: 'FULL', featureSet: 'FULL',
@ -69,6 +71,7 @@ Clipperz.PM.UI.Components.Pages.MainPageClass = React.createClass({
result = React.DOM.div({'key':'mainPage', 'className':Clipperz.PM.UI.Components.classNames(classes)}, [ result = React.DOM.div({'key':'mainPage', 'className':Clipperz.PM.UI.Components.classNames(classes)}, [
Clipperz.PM.UI.Components.AttachmentQueueBox(this.props), Clipperz.PM.UI.Components.AttachmentQueueBox(this.props),
Clipperz.PM.UI.Components.CertificateQueueBox(this.props),
this.props['style'] != 'extra-wide' ? Clipperz.PM.UI.Components.Panels.SelectionPanel(this.props) : null, this.props['style'] != 'extra-wide' ? Clipperz.PM.UI.Components.Panels.SelectionPanel(this.props) : null,
Clipperz.PM.UI.Components.Panels.MainPanel(this.props), Clipperz.PM.UI.Components.Panels.MainPanel(this.props),
Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanel(this.props), Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanel(this.props),

View File

@ -25,6 +25,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.Pages');
Clipperz.PM.UI.Components.Pages.RegistrationPageClass = React.createClass({ Clipperz.PM.UI.Components.Pages.RegistrationPageClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.Pages.RegistrationPage',
getDefaultProps: function () { getDefaultProps: function () {
return { return {
steps: [ steps: [
@ -126,8 +128,8 @@ Clipperz.PM.UI.Components.Pages.RegistrationPageClass = React.createClass({
toggleCheckbox: function (aCheckboxRef, anEvent) { toggleCheckbox: function (aCheckboxRef, anEvent) {
var newState = {}; var newState = {};
this.refs[aCheckboxRef].getDOMNode().checked = ! this.refs[aCheckboxRef].getDOMNode().checked; this.refs[aCheckboxRef].checked = ! this.refs[aCheckboxRef].checked;
newState[aCheckboxRef] = this.refs[aCheckboxRef].getDOMNode().checked; newState[aCheckboxRef] = this.refs[aCheckboxRef].checked;
this.setState(newState); this.setState(newState);
}, },
@ -154,7 +156,7 @@ Clipperz.PM.UI.Components.Pages.RegistrationPageClass = React.createClass({
handleChange: function (anEvent) { handleChange: function (anEvent) {
var refs = this.refs; var refs = this.refs;
var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName].getDOMNode() == anEvent.target}, MochiKit.Base.keys(this.refs))[0]; var refName = MochiKit.Base.filter(function (aRefName) { return refs[aRefName] == anEvent.target}, MochiKit.Base.keys(this.refs))[0];
var newState = {}; var newState = {};
if ((anEvent.target.type == 'checkbox') || (anEvent.target.type == 'radio')) { if ((anEvent.target.type == 'checkbox') || (anEvent.target.type == 'radio')) {
@ -213,12 +215,12 @@ Clipperz.PM.UI.Components.Pages.RegistrationPageClass = React.createClass({
return React.DOM.div({'key':'termsOfService'}, [ return React.DOM.div({'key':'termsOfService'}, [
React.DOM.div({'key':'termsOfService_choice_1', 'className':'checkboxBlock'}, [ React.DOM.div({'key':'termsOfService_choice_1', 'className':'checkboxBlock'}, [
React.DOM.label({'key':'termsOfService_label_1', 'htmlFor':'no_password_recovery'}, "I understand that Clipperz is unable to recover a lost passphrase."), React.DOM.label({'key':'termsOfService_label_1', 'htmlFor':'no_password_recovery'}, "I understand that Clipperz is unable to recover a lost passphrase."),
React.DOM.input({'key':'no_password_recovery', 'type':'checkbox', 'name':'no_password_recovery', 'ref':'no_password_recovery', 'id':'no_password_recovery', 'tabindex':'0'}), React.DOM.input({'key':'no_password_recovery', 'type':'checkbox', 'name':'no_password_recovery', 'ref':'no_password_recovery', 'id':'no_password_recovery', 'tabIndex':'0'}),
React.DOM.p({'key':'termsOfService_description_1', 'onClick':MochiKit.Base.method(this, 'toggleCheckbox', 'no_password_recovery')}, "I understand that Clipperz is unable to recover a lost passphrase.") React.DOM.p({'key':'termsOfService_description_1', 'onClick':MochiKit.Base.method(this, 'toggleCheckbox', 'no_password_recovery')}, "I understand that Clipperz is unable to recover a lost passphrase.")
]), ]),
React.DOM.div({'key':'termsOfService_choice_2', 'className':'checkboxBlock'}, [ React.DOM.div({'key':'termsOfService_choice_2', 'className':'checkboxBlock'}, [
React.DOM.label({'key':'termsOfService_label_2', 'htmlFor':'agree_terms_of_service'}, "I have read and agreed to the Terms of Service."), React.DOM.label({'key':'termsOfService_label_2', 'htmlFor':'agree_terms_of_service'}, "I have read and agreed to the Terms of Service."),
React.DOM.input({'key':'agree_terms_of_service', 'type':'checkbox', 'name':'agree_terms_of_service', 'ref':'agree_terms_of_service', 'id':'agree_terms_of_service', 'tabindex':'1'}), React.DOM.input({'key':'agree_terms_of_service', 'type':'checkbox', 'name':'agree_terms_of_service', 'ref':'agree_terms_of_service', 'id':'agree_terms_of_service', 'tabIndex':'1'}),
React.DOM.p({'key':'termsOfService_description_2'}, [ React.DOM.p({'key':'termsOfService_description_2'}, [
React.DOM.span({'key':'termsOfService_description_2_p1', 'onClick':MochiKit.Base.method(this, 'toggleCheckbox', 'agree_terms_of_service')}, "I have read and agreed to the "), React.DOM.span({'key':'termsOfService_description_2_p1', 'onClick':MochiKit.Base.method(this, 'toggleCheckbox', 'agree_terms_of_service')}, "I have read and agreed to the "),
React.DOM.a({'key':'termsOfService_description_2_p2', 'onClick':this.showUrl('/terms_service/')}, "Terms of Service.") React.DOM.a({'key':'termsOfService_description_2_p2', 'onClick':this.showUrl('/terms_service/')}, "Terms of Service.")
@ -290,15 +292,15 @@ Clipperz.PM.UI.Components.Pages.RegistrationPageClass = React.createClass({
//========================================================================= //=========================================================================
setInitialFocus: function () { setInitialFocus: function () {
this.refs['username'].getDOMNode().focus(); this.refs['username'].focus();
}, },
componentDidUpdate: function (prevProps, prevState, rootNode) { componentDidUpdate: function (prevProps, prevState, rootNode) {
if (prevState['currentStep'] != this.state['currentStep']) { if (prevState['currentStep'] != this.state['currentStep']) {
if (this.state['currentStep'] == 'CREDENTIALS') { if (this.state['currentStep'] == 'CREDENTIALS') {
this.refs['passphrase'].getDOMNode().select(); this.refs['passphrase'].select();
} else if (this.state['currentStep'] == 'PASSWORD_VERIFICATION') { } else if (this.state['currentStep'] == 'PASSWORD_VERIFICATION') {
this.refs['verify_passphrase'].getDOMNode().select(); this.refs['verify_passphrase'].select();
} }
} }
} }

View File

@ -26,10 +26,12 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.Pages');
Clipperz.PM.UI.Components.Pages.UnlockPageClass = React.createClass({ Clipperz.PM.UI.Components.Pages.UnlockPageClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.Pages.UnlockPage',
propTypes: { propTypes: {
username: React.PropTypes.string.isRequired, // username: React.PropTypes.string.isRequired,
mode: React.PropTypes.oneOf(['CREDENTIALS','PIN']).isRequired, mode: React.PropTypes.oneOf(['CREDENTIALS','PIN']).isRequired,
disabled: React.PropTypes.bool.isRequired, // disabled: React.PropTypes.bool.isRequired,
}, },
getInitialState: function () { getInitialState: function () {
@ -70,29 +72,29 @@ Clipperz.PM.UI.Components.Pages.UnlockPageClass = React.createClass({
handlePassphraseSubmit: function (event) { handlePassphraseSubmit: function (event) {
event.preventDefault(); event.preventDefault();
this.refs['passphrase'].getDOMNode().blur(); this.refs['passphrase'].blur();
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'unlock', this.refs['passphrase'].getDOMNode().value, 'PASSPHRASE'); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'unlock', {'credential':this.refs['passphrase'].value, 'credentialType':'PASSPHRASE'});
// this.resetUnlockForm(); // this.resetUnlockForm();
}, },
submitPIN: function() { submitPIN: function() {
this.refs['pin'].getDOMNode().blur(); this.refs['pin'].blur();
var pin = this.refs['pin'].getDOMNode().value; var pin = this.refs['pin'].value;
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'unlock', pin, 'PIN'); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'unlock', {'credential':pin, 'credentialType':'PIN'});
// this.resetUnlockForm(); // this.resetUnlockForm();
}, },
resetUnlockForm: function() { resetUnlockForm: function() {
if (this.mode() == 'CREDENTIALS') { if (this.mode() == 'CREDENTIALS') {
this.refs['passphrase'].getDOMNode().value = ''; this.refs['passphrase'].value = '';
this.refs['passphrase'].getDOMNode().blur(); this.refs['passphrase'].blur();
} else if (this.mode() == 'PIN') { } else if (this.mode() == 'PIN') {
this.refs['pin'].getDOMNode().value = ''; this.refs['pin'].value = '';
this.refs['pin'].getDOMNode().blur(); this.refs['pin'].blur();
} }
}, },
@ -104,9 +106,9 @@ Clipperz.PM.UI.Components.Pages.UnlockPageClass = React.createClass({
setInitialFocus: function () { setInitialFocus: function () {
if (this.mode() == 'PIN') { if (this.mode() == 'PIN') {
this.refs['pin'].getDOMNode().focus(); this.refs['pin'].focus();
} else { } else {
this.refs['passphrase'].getDOMNode().focus(); this.refs['passphrase'].focus();
} }
}, },

View File

@ -26,12 +26,13 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.Panels');
Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanelClass = React.createClass({ Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanelClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanel',
componentDidMount: function () { componentDidMount: function () {
MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, 'closeSettingsPanel', MochiKit.Base.method(this, 'hideExtraFeatureContent')); MochiKit.Signal.connect(Clipperz.Signal.NotificationCenter, 'closeSettingsPanel', MochiKit.Base.method(this, 'hideExtraFeatureContent'));
}, },
settingsToggleHandler: function (anEvent) { settingsToggleHandler: function (anEvent) {
//console.log("settingsToggleHandler");
this.hideExtraFeatureContent(); this.hideExtraFeatureContent();
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'toggleSettingsPanel'); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'toggleSettingsPanel');
}, },
@ -120,6 +121,10 @@ Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanelClass = React.createClass({
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'updateOTPListAndDetails'); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'updateOTPListAndDetails');
} }
if (aComponentName == 'Plan') {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'updateUserAccountInfo');
}
this.setState({ this.setState({
'isFullyOpen':true, 'isFullyOpen':true,
'extraFeatureComponentName': aComponentName, 'extraFeatureComponentName': aComponentName,
@ -147,23 +152,29 @@ Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanelClass = React.createClass({
React.DOM.li({'key':'account', 'className':this.state['index']['account'] ? 'open' : 'closed'}, [ React.DOM.li({'key':'account', 'className':this.state['index']['account'] ? 'open' : 'closed'}, [
React.DOM.h1({'key':'accountH1', 'onClick':this.toggleIndexState('account')}, "Account"), React.DOM.h1({'key':'accountH1', 'onClick':this.toggleIndexState('account')}, "Account"),
React.DOM.ul({'key':'accountUL'}, [ React.DOM.ul({'key':'accountUL'}, [
React.DOM.li({'key':'account_preferences', 'onClick':this.toggleExtraFeatureComponent('Preferences'), 'className':(this.state['extraFeatureComponentName'] == 'Preferences') ? 'selected' : ''}, [ React.DOM.li({'key':'account_0', 'onClick':this.toggleExtraFeatureComponent('Preferences'), 'className':(this.state['extraFeatureComponentName'] == 'Preferences') ? 'selected' : ''}, [
React.DOM.h2({'key':'account_preferences_h2'}, "Preferences"), React.DOM.h2({}, "Preferences"),
]), ]),
React.DOM.li({'key':'account_1', 'onClick':this.toggleExtraFeatureComponent('Passphrase'), 'className':(this.state['extraFeatureComponentName'] == 'Passphrase') ? 'selected' : ''}, [ React.DOM.li({'key':'account_1', 'onClick':this.toggleExtraFeatureComponent('Passphrase'), 'className':(this.state['extraFeatureComponentName'] == 'Passphrase') ? 'selected' : ''}, [
React.DOM.h2({'key':'account_1_h2'}, "Passphrase"), React.DOM.h2({}, "Passphrase"),
// React.DOM.div({'key':'account_1_div'}, [ // React.DOM.div({'key':'account_1_div'}, [
// React.DOM.p({'key':'account_1_p'}, "Change your account passphrase.") // React.DOM.p({'key':'account_1_p'}, "Change your account passphrase.")
// ]) // ])
]), ]),
React.DOM.li({'key':'account_2', 'onClick':this.toggleExtraFeatureComponent('OTP')}, [ React.DOM.li({'key':'account_2', 'onClick':this.toggleExtraFeatureComponent('Plan'), 'className':(this.state['extraFeatureComponentName'] == 'Plan') ? 'selected' : ''}, [
React.DOM.h2({}, "Plan"),
// React.DOM.div({}, [
// React.DOM.p({}, "Current plan.")
// ])
]),
React.DOM.li({'key':'account_3', 'onClick':this.toggleExtraFeatureComponent('OTP')}, [
React.DOM.h2({}, "One-Time Passwords"), React.DOM.h2({}, "One-Time Passwords"),
// React.DOM.div({}, [ // React.DOM.div({}, [
// React.DOM.p({}, "Manage your OTPs.") // React.DOM.p({}, "Manage your OTPs.")
// ]) // ])
]), ]),
React.DOM.li({'key':'account_3', 'onClick':this.toggleExtraFeatureComponent('DevicePIN')}, [ React.DOM.li({'key':'account_4', 'onClick':this.toggleExtraFeatureComponent('DevicePIN')}, [
React.DOM.h2({}, "Device PIN"), React.DOM.h2({}, "Device PIN"),
// React.DOM.div({}, [ // React.DOM.div({}, [
// React.DOM.p({}, "Configure a PIN that will allow to get access to your cards, but only on this device.") // React.DOM.p({}, "Configure a PIN that will allow to get access to your cards, but only on this device.")

View File

@ -28,6 +28,8 @@ Clipperz.PM.UI.Components.Panels.MainPanelClass = React.createClass({
//========================================================================= //=========================================================================
displayName: 'Clipperz.PM.UI.Components.Panels.MainPanel',
propTypes: { propTypes: {
'allTags': React.PropTypes.array, 'allTags': React.PropTypes.array,
'messageBox': React.PropTypes.object.isRequired, 'messageBox': React.PropTypes.object.isRequired,

View File

@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components.Panels');
Clipperz.PM.UI.Components.Panels.SelectionPanelClass = React.createClass({ Clipperz.PM.UI.Components.Panels.SelectionPanelClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.Panels.SelectionPanel',
propTypes: { propTypes: {
selectionPanelStatus: React.PropTypes.oneOf(['OPEN', 'CLOSED']).isRequired selectionPanelStatus: React.PropTypes.oneOf(['OPEN', 'CLOSED']).isRequired
}, },

View File

@ -26,6 +26,8 @@ Clipperz.Base.module('Clipperz.PM.UI.Components');
Clipperz.PM.UI.Components.RadialProgressIndicatorClass = React.createClass({ Clipperz.PM.UI.Components.RadialProgressIndicatorClass = React.createClass({
displayName: 'Clipperz.PM.UI.Components.RadialProgressIndicator',
propTypes: { propTypes: {
'progress': React.PropTypes.number.isRequired, 'progress': React.PropTypes.number.isRequired,
}, },

View File

@ -28,6 +28,8 @@ Clipperz.PM.UI.Components.SelectionsClass = React.createClass({
//========================================================================= //=========================================================================
displayName: 'Clipperz.PM.UI.Components.Selections',
selectAll: function (anEvent) { selectAll: function (anEvent) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectAllCards'); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectAllCards');
}, },
@ -36,6 +38,10 @@ Clipperz.PM.UI.Components.SelectionsClass = React.createClass({
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectRecentCards'); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectRecentCards');
}, },
selectWithCertificate: function (anEvent) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectCardsWithCertificate');
},
selectWithAttachments: function (anEvent) { selectWithAttachments: function (anEvent) {
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectCardsWithAttachments'); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'selectCardsWithAttachments');
}, },
@ -99,6 +105,10 @@ Clipperz.PM.UI.Components.SelectionsClass = React.createClass({
React.DOM.span({'className':'label'}, "Recent"), React.DOM.span({'className':'label'}, "Recent"),
React.DOM.span({'className':'count'}, this.props['allCardsCount'] ? '10' : '-') React.DOM.span({'className':'count'}, this.props['allCardsCount'] ? '10' : '-')
]), ]),
React.DOM.li({'className':'withCertificateCards', 'onClick': this.selectWithCertificate}, [
React.DOM.span({'className':'label'}, "With certificate"),
React.DOM.span({'className':'count'}, this.props['withCertificateCardsCount'] ? this.props['withCertificateCardsCount'] : '-')
]),
React.DOM.li({'className':'withAttachmentCards', 'onClick': this.selectWithAttachments}, [ React.DOM.li({'className':'withAttachmentCards', 'onClick': this.selectWithAttachments}, [
React.DOM.span({'className':'label'}, "With attachments"), React.DOM.span({'className':'label'}, "With attachments"),
React.DOM.span({'className':'count'}, this.props['withAttachmentCardsCount'] ? this.props['withAttachmentCardsCount'] : '-') React.DOM.span({'className':'count'}, this.props['withAttachmentCardsCount'] ? this.props['withAttachmentCardsCount'] : '-')

View File

@ -28,6 +28,8 @@ Clipperz.PM.UI.Components.TagIndexItemClass = React.createClass({
//========================================================================= //=========================================================================
displayName: 'Clipperz.PM.UI.Components.TagIndexItem',
propTypes: { propTypes: {
'label': React.PropTypes.string.isRequired, 'label': React.PropTypes.string.isRequired,
'count': React.PropTypes.number.isRequired, 'count': React.PropTypes.number.isRequired,

View File

@ -33,7 +33,7 @@ Clipperz.PM.UI.ExportController = function(args) {
this._style = this._style =
"body {" + "body {" +
"font-family: 'Dejavu Sans', monospace;" + "font-family: 'DejaVu Sans Mono', monospace;" +
"margin: 0px;" + "margin: 0px;" +
"}" + "}" +

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,3 @@
/*
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/.
*/
/* Blob.js /* Blob.js
* A Blob implementation. * A Blob implementation.
* 2014-07-24 * 2014-07-24

View File

@ -1,26 +1,3 @@
/*
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/.
*/
/* FileSaver.js /* FileSaver.js
* A saveAs() FileSaver implementation. * A saveAs() FileSaver implementation.
* 2015-03-04 * 2015-03-04

View File

@ -1,26 +1,3 @@
/*
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/.
*/
/** /**
* filesize * filesize
* *

View File

@ -1,26 +1,3 @@
/*
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"; "use strict";
/** /**

View File

@ -1,26 +1,3 @@
/*
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/.
*/
/* /*
2015 2015
@version 3.1.3 @version 3.1.3

View File

@ -1,26 +1,3 @@
/*
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/.
*/
/*! /*!
* Modernizr v2.8.2 * Modernizr v2.8.2
* www.modernizr.com * www.modernizr.com

View File

@ -1,26 +1,3 @@
/*
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/.
*/
/*! /*!
Papa Parse Papa Parse
v4.1.1 v4.1.1

View File

@ -1,26 +1,3 @@
/*
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/.
*/
/*! /*!
Papa Parse Papa Parse
v4.1.1 v4.1.1

View File

@ -1,26 +1,3 @@
/*
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/.
*/
(function () { (function () {
global = this global = this

View File

@ -1,24 +1 @@
/*
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/.
*/
!function(){function a(a){global.setImmediate?setImmediate(a):global.importScripts?setTimeout(a):(c++,d[c]=a,global.postMessage(c,"*"))}function b(c){"use strict";function d(a,b,c,d){if("object"!=typeof j&&"function"!=typeof j||"function"!=typeof a)d();else try{var e=0;a.call(j,function(a){e++||(j=a,b())},function(a){e++||(j=a,c())})}catch(f){j=f,c()}}function e(){var a;try{a=j&&j.then}catch(b){return j=b,i=2,e()}d(a,function(){i=1,e()},function(){i=2,e()},function(){try{1==i&&"function"==typeof f?j=f(j):2==i&&"function"==typeof g&&(j=g(j),i=1)}catch(b){return j=b,l()}j==h?(j=TypeError(),l()):d(a,function(){l(3)},l,function(){l(1==i&&3)})})}if("function"!=typeof c&&void 0!=c)throw TypeError();if("object"!=typeof this||this&&this.then)throw TypeError();var f,g,h=this,i=0,j=0,k=[];h.promise=h,h.resolve=function(b){return f=h.fn,g=h.er,i||(j=b,i=1,a(e)),h},h.reject=function(b){return f=h.fn,g=h.er,i||(j=b,i=2,a(e)),h},h._d=1,h.then=function(a,c){if(1!=this._d)throw TypeError();var d=new b;return d.fn=a,d.er=c,3==i?d.resolve(j):4==i?d.reject(j):k.push(d),d},h["catch"]=function(a){return h.then(null,a)};var l=function(a){i=a||4,k.map(function(a){3==i&&a.resolve(j)||a.reject(j)})};try{"function"==typeof c&&c(h.resolve,h.reject)}catch(m){h.reject(m)}return h}global=this;var c=1,d={},e=!1;global.setImmediate||global.addEventListener("message",function(b){if(b.source==global)if(e)a(d[b.data]);else{e=!0;try{d[b.data]()}catch(b){}delete d[b.data],e=!1}}),b.resolve=function(a){if(1!=this._d)throw TypeError();return a instanceof b?a:new b(function(b){b(a)})},b.reject=function(a){if(1!=this._d)throw TypeError();return new b(function(b,c){c(a)})},b.all=function(a){function c(b,e){if(e)return d.resolve(e);if(b)return d.reject(b);var f=a.reduce(function(a,b){return b&&b.then?a+1:a},0);0==f&&d.resolve(a),a.map(function(b,d){b&&b.then&&b.then(function(b){return a[d]=b,c(),b},c)})}if(1!=this._d)throw TypeError();if(!(a instanceof Array))return b.reject(TypeError());var d=new b;return c(),d},b.race=function(a){function c(b,e){if(e)return d.resolve(e);if(b)return d.reject(b);var f=a.reduce(function(a,b){return b&&b.then?a+1:a},0);0==f&&d.resolve(a),a.map(function(a,b){a&&a.then&&a.then(function(a){c(null,a)},c)})}if(1!=this._d)throw TypeError();if(!(a instanceof Array))return b.reject(TypeError());if(0==a.length)return new b;var d=new b;return c(),d},b._d=1,"undefined"!=typeof module?module.exports=b:global.Promise=global.Promise||b}(); !function(){function a(a){global.setImmediate?setImmediate(a):global.importScripts?setTimeout(a):(c++,d[c]=a,global.postMessage(c,"*"))}function b(c){"use strict";function d(a,b,c,d){if("object"!=typeof j&&"function"!=typeof j||"function"!=typeof a)d();else try{var e=0;a.call(j,function(a){e++||(j=a,b())},function(a){e++||(j=a,c())})}catch(f){j=f,c()}}function e(){var a;try{a=j&&j.then}catch(b){return j=b,i=2,e()}d(a,function(){i=1,e()},function(){i=2,e()},function(){try{1==i&&"function"==typeof f?j=f(j):2==i&&"function"==typeof g&&(j=g(j),i=1)}catch(b){return j=b,l()}j==h?(j=TypeError(),l()):d(a,function(){l(3)},l,function(){l(1==i&&3)})})}if("function"!=typeof c&&void 0!=c)throw TypeError();if("object"!=typeof this||this&&this.then)throw TypeError();var f,g,h=this,i=0,j=0,k=[];h.promise=h,h.resolve=function(b){return f=h.fn,g=h.er,i||(j=b,i=1,a(e)),h},h.reject=function(b){return f=h.fn,g=h.er,i||(j=b,i=2,a(e)),h},h._d=1,h.then=function(a,c){if(1!=this._d)throw TypeError();var d=new b;return d.fn=a,d.er=c,3==i?d.resolve(j):4==i?d.reject(j):k.push(d),d},h["catch"]=function(a){return h.then(null,a)};var l=function(a){i=a||4,k.map(function(a){3==i&&a.resolve(j)||a.reject(j)})};try{"function"==typeof c&&c(h.resolve,h.reject)}catch(m){h.reject(m)}return h}global=this;var c=1,d={},e=!1;global.setImmediate||global.addEventListener("message",function(b){if(b.source==global)if(e)a(d[b.data]);else{e=!0;try{d[b.data]()}catch(b){}delete d[b.data],e=!1}}),b.resolve=function(a){if(1!=this._d)throw TypeError();return a instanceof b?a:new b(function(b){b(a)})},b.reject=function(a){if(1!=this._d)throw TypeError();return new b(function(b,c){c(a)})},b.all=function(a){function c(b,e){if(e)return d.resolve(e);if(b)return d.reject(b);var f=a.reduce(function(a,b){return b&&b.then?a+1:a},0);0==f&&d.resolve(a),a.map(function(b,d){b&&b.then&&b.then(function(b){return a[d]=b,c(),b},c)})}if(1!=this._d)throw TypeError();if(!(a instanceof Array))return b.reject(TypeError());var d=new b;return c(),d},b.race=function(a){function c(b,e){if(e)return d.resolve(e);if(b)return d.reject(b);var f=a.reduce(function(a,b){return b&&b.then?a+1:a},0);0==f&&d.resolve(a),a.map(function(a,b){a&&a.then&&a.then(function(a){c(null,a)},c)})}if(1!=this._d)throw TypeError();if(!(a instanceof Array))return b.reject(TypeError());if(0==a.length)return new b;var d=new b;return c(),d},b._d=1,"undefined"!=typeof module?module.exports=b:global.Promise=global.Promise||b}();

View File

@ -0,0 +1,42 @@
/**
* ReactDOM v0.14.7
*
* Copyright 2013-2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
// Based off https://github.com/ForbesLindesay/umd/blob/master/template.js
;(function(f) {
// CommonJS
if (typeof exports === "object" && typeof module !== "undefined") {
module.exports = f(require('react'));
// RequireJS
} else if (typeof define === "function" && define.amd) {
define(['react'], f);
// <script>
} else {
var g;
if (typeof window !== "undefined") {
g = window;
} else if (typeof global !== "undefined") {
g = global;
} else if (typeof self !== "undefined") {
g = self;
} else {
// works providing we're not in "use strict";
// needed for Java 8 Nashorn
// see https://github.com/facebook/react/issues/3037
g = this;
}
g.ReactDOM = f(g.React);
}
})(function(React) {
return React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
});

View File

@ -0,0 +1,12 @@
/**
* ReactDOM v0.14.7
*
* Copyright 2013-2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e(require("react"));else if("function"==typeof define&&define.amd)define(["react"],e);else{var f;f="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,f.ReactDOM=e(f.React)}}(function(e){return e.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,26 +1,3 @@
/*
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/.
*/
/** /**
* @file Web Cryptography API shim * @file Web Cryptography API shim
* @author Artem S Vybornov <vybornov@gmail.com> * @author Artem S Vybornov <vybornov@gmail.com>

View File

@ -43,7 +43,7 @@ MochiKit.Logging.logError("## MainController - GENERIC ERROR" + "\n" + "==>> " +
return result; return result;
} }
React.initializeTouchEvents(true); //React.initializeTouchEvents(true);
Clipperz.PM.RunTime = {}; Clipperz.PM.RunTime = {};

View File

@ -0,0 +1,9 @@
var npm = {
base58: require('bs58'),
bitcoin: require('bitcoinjs-lib'),
ecurve: require('ecurve'),
BigInteger: require('bigi'),
buffer: require('buffer')
}
module.exports = npm

12609
frontend/delta/js/npm/npm.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,26 +1,3 @@
/*
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/.
*/
/** /**
* @preserve XDate v@VERSION * @preserve XDate v@VERSION
* Docs & Licensing: http://arshaw.com/xdate/ * Docs & Licensing: http://arshaw.com/xdate/

View File

@ -37,6 +37,36 @@
* Copyright (c) 2000-2013, Leemon Baird * Copyright (c) 2000-2013, Leemon Baird
* License: Public Domain * License: Public Domain
# PapaParse (https://github.com/mholt/PapaParse)
* Repository: @papaparse.repository@ (version: @papaparse.version@ - commit: @papaparse.commit@)
* Copyright (c) 2015 Matthew Holt
* License: http://opensource.org/licenses/mit-license.php
# xDate (http://arshaw.com/xdate/)
* Repository: @xDate.repository@ (version: @xDate.version@ - commit: @xDate.commit@)
* Copyright (c) 2011 Adam Shaw, http://arshaw.com/xdate/
* License: http://opensource.org/licenses/mit-license.php
# FileSize (http://filesizejs.com)
* Repository: @filesize.repository@ (version: @filesize.version@ - commit: @filesize.commit@)
* Copyright (c) 2015, Jason Mulligan
* License: https://github.com/avoidwork/filesize.js/blob/master/LICENSE
# Promiz (https://github.com/Zolmeister/promiz.git)
* Repository: @promiz.repository@ (version: @promiz.version@ - commit: @promiz.commit@)
* Copyright (c) 2014 Zolmeister
* License: http://opensource.org/licenses/mit-license.php
# WebCryptoShim (https://vibornoff.github.io/webcrypto-shim/)
* Repository: @webcryptoshim.repository@ (version: @webcryptoshim.version@ - commit: @webcryptoshim.commit@)
* Copyright (c) 2015 Artem S Vybornov
* License: http://opensource.org/licenses/mit-license.php
# BitCoinJS-lib (http://bitcoinjs.org)
* Repository: @bitcoinjs-lib.repository@ (version: @bitcoinjs-lib.version@ - commit: @bitcoinjs-lib.commit@)
* Copyright (c) 2011-2016 bitcoinjs-lib contributors
* License: http://opensource.org/licenses/mit-license.php
=============================================================================== ===============================================================================
Other code snippets used in the first demo of the program, and still Other code snippets used in the first demo of the program, and still

View File

@ -42,7 +42,15 @@
"webcryptoshim.repository": "https://github.com/vibornoff/webcrypto-shim.git", "webcryptoshim.repository": "https://github.com/vibornoff/webcrypto-shim.git",
"webcryptoshim.version": "0.1.0", "webcryptoshim.version": "0.1.0",
"webcryptoshim.commit": "fb82fe0936adb4813a9b513991266a2bef51d32b" "webcryptoshim.commit": "fb82fe0936adb4813a9b513991266a2bef51d32b",
"bitcoinjs-lib.repository": "https://github.com/bitcoinjs/bitcoinjs-lib",
"bitcoinjs-lib.version": "2.1.4",
"bitcoinjs-lib.commit": "e25ce449dcd932d34d15e47a269a54ea155bdb4d",
"buffer.repository": "https://github.com/feross/buffer",
"buffer.version": "4.3.0",
"buffer.commit": "e52c33af77a79060c4d423a5447bd77c331ee9c9"
}, },
"html.template": "index_template.html", "html.template": "index_template.html",
@ -63,10 +71,10 @@
"MochiKit/Selector.js", "MochiKit/Selector.js",
"-- MochiKit/Visual.js", "-- MochiKit/Visual.js",
"-- React/react-0.13.3.js", "-- React/react-0.14.7.js",
"React/react.min-0.13.3.js", "-- React/react-dom-0.14.7.js",
"-- #React/react-with-addons-0.13.1.js", "React/react.min-0.14.7.js",
"-- #React/react-with-addons.min-0.13.1.js", "React/react-dom.min-0.14.7.js",
"MouseTrap/mousetrap.js", "MouseTrap/mousetrap.js",
"-- MouseTrap/mousetrap-bind-dictionary.js", "-- MouseTrap/mousetrap-bind-dictionary.js",
@ -84,7 +92,7 @@
"PapaParse/papaparse.js", "PapaParse/papaparse.js",
"-- PapaParse/papaparse.min.js", "-- PapaParse/papaparse.min.js",
"xDate/xdate.js", "xDate/xdate-0.8.js",
"-- Filesize/filesize.js", "-- Filesize/filesize.js",
"Filesize/filesize.min.js", "Filesize/filesize.min.js",
@ -93,6 +101,8 @@
"Promiz/promiz.min.js", "Promiz/promiz.min.js",
"WebcryptoShim/webcrypto-shim.js", "WebcryptoShim/webcrypto-shim.js",
"npm/npm.js",
"-- IT WOULD BE NICE TO BE ABLE TO GET RID OF THESE IMPORTS", "-- IT WOULD BE NICE TO BE ABLE TO GET RID OF THESE IMPORTS",
"Clipperz/YUI/Utils.js", "Clipperz/YUI/Utils.js",
"Clipperz/YUI/DomHelper.js", "Clipperz/YUI/DomHelper.js",
@ -163,6 +173,7 @@
"Clipperz/PM/DataModel/User.Header.RecordIndex.js", "Clipperz/PM/DataModel/User.Header.RecordIndex.js",
"Clipperz/PM/DataModel/User.Header.Preferences.js", "Clipperz/PM/DataModel/User.Header.Preferences.js",
"Clipperz/PM/DataModel/User.Header.OneTimePasswords.js", "Clipperz/PM/DataModel/User.Header.OneTimePasswords.js",
"Clipperz/PM/DataModel/User.Header.Wallet.js",
"Clipperz/PM/DataModel/User.AccountInfo.js", "Clipperz/PM/DataModel/User.AccountInfo.js",
"Clipperz/PM/DataModel/Record.js", "Clipperz/PM/DataModel/Record.js",
"Clipperz/PM/DataModel/Record.Version.js", "Clipperz/PM/DataModel/Record.Version.js",
@ -195,6 +206,7 @@
"Clipperz/PM/UI/Components/TagIndexItem.js", "Clipperz/PM/UI/Components/TagIndexItem.js",
"Clipperz/PM/UI/Components/Help.js", "Clipperz/PM/UI/Components/Help.js",
"Clipperz/PM/UI/Components/AttachmentQueueBox.js", "Clipperz/PM/UI/Components/AttachmentQueueBox.js",
"Clipperz/PM/UI/Components/CertificateQueueBox.js",
"Clipperz/PM/UI/Components/RadialProgressIndicator.js", "Clipperz/PM/UI/Components/RadialProgressIndicator.js",
"Clipperz/PM/UI/Components/ExpiredPanel.js", "Clipperz/PM/UI/Components/ExpiredPanel.js",
@ -213,6 +225,7 @@
"Clipperz/PM/UI/Components/ExtraFeatures/DevicePIN.js", "Clipperz/PM/UI/Components/ExtraFeatures/DevicePIN.js",
"Clipperz/PM/UI/Components/ExtraFeatures/Preferences.js", "Clipperz/PM/UI/Components/ExtraFeatures/Preferences.js",
"Clipperz/PM/UI/Components/ExtraFeatures/Passphrase.js", "Clipperz/PM/UI/Components/ExtraFeatures/Passphrase.js",
"Clipperz/PM/UI/Components/ExtraFeatures/Plan.js",
"Clipperz/PM/UI/Components/ExtraFeatures/OTP.js", "Clipperz/PM/UI/Components/ExtraFeatures/OTP.js",
"Clipperz/PM/UI/Components/ExtraFeatures/DeleteAccount.js", "Clipperz/PM/UI/Components/ExtraFeatures/DeleteAccount.js",
"Clipperz/PM/UI/Components/ExtraFeatures/DataExport.js", "Clipperz/PM/UI/Components/ExtraFeatures/DataExport.js",
@ -238,6 +251,8 @@
"Clipperz/PM/UI/Components/Cards/EditToolbar.js", "Clipperz/PM/UI/Components/Cards/EditToolbar.js",
"Clipperz/PM/UI/Components/Cards/TagEditor.js", "Clipperz/PM/UI/Components/Cards/TagEditor.js",
"Clipperz/PM/UI/Components/Cards/PasswordGenerator.js", "Clipperz/PM/UI/Components/Cards/PasswordGenerator.js",
"Clipperz/PM/UI/Components/Cards/CertificateRenderer.js",
"Clipperz/PM/UI/Components/AccountStatus.js", "Clipperz/PM/UI/Components/AccountStatus.js",
@ -245,6 +260,7 @@
"-- Clipperz/PM/UI/MainDesktopController.js", "-- Clipperz/PM/UI/MainDesktopController.js",
"Clipperz/PM/UI/DirectLoginController.js", "Clipperz/PM/UI/DirectLoginController.js",
"Clipperz/PM/UI/ExportController.js", "Clipperz/PM/UI/ExportController.js",
"Clipperz/PM/UI/CertificateDownloadController.js",
"Clipperz/PM/UI/AttachmentController.js", "Clipperz/PM/UI/AttachmentController.js",
"Clipperz/PM/UI/ImportContext.js", "Clipperz/PM/UI/ImportContext.js",
"main.js" "main.js"

View File

@ -36,6 +36,7 @@ refer to http://www.clipperz.com.
@import "style/loadingPage"; @import "style/loadingPage";
@import "style/loginPage"; @import "style/loginPage";
@import "style/errorPage";
@import "style/selectionPanel"; @import "style/selectionPanel";
@import "style/settingsPanel"; @import "style/settingsPanel";
@import "style/accountStatus"; @import "style/accountStatus";

File diff suppressed because one or more lines are too long

View File

@ -109,6 +109,7 @@ input[type=text] {
&.selection { &.selection {
@include flex($selectionPanelFlexWidth, 0); @include flex($selectionPanelFlexWidth, 0);
max-width: 20%;
// height: 100%; // height: 100%;
// @include overflow-auto; // @include overflow-auto;
} }
@ -326,6 +327,8 @@ div.cardToolbar {
@include flex(4); @include flex(4);
text-align: center; text-align: center;
font-size: 28pt;
&.tag, &.search { &.tag, &.search {
font-size: 14pt; font-size: 14pt;
} }
@ -374,17 +377,16 @@ div.cardToolbar {
h3 { h3 {
font-weight: bold; font-weight: bold;
font-size: 33pt; font-size: 32pt;
letter-spacing: -12px;
letter-spacing: -10px;
} }
.badge { .badge {
position: absolute; position: absolute;
margin-left: -12px; margin-left: -8px;
width: auto; width: auto;
height: 16px; height: 16px;
line-height: 17px; line-height: 16px;
background-color: #1863a1; background-color: #1863a1;
color: white; color: white;
text-align: center; text-align: center;
@ -399,10 +401,49 @@ div.cardToolbar {
&.bottom { &.bottom {
top: 25px; top: 25px;
margin-left: -42px; margin-left: -36px;
} }
} }
} }
.certificateQueueToggleButton {
@include icon-font();
margin-right: 10px;
h3 {
font-weight: bold;
font-size: 22pt;
letter-spacing: -12px;
line-height: 34pt;
}
.badge {
position: absolute;
margin-left: -4px;
width: auto;
height: 16px;
line-height: 16px;
// background-color: #1863a1;
color: white;
text-align: center;
font-size: 8pt;
font-weight: bold;
border-radius: 8px;
padding: 0px 4px;
&.top {
top: 8px;
background-color: #666;
}
&.bottom {
top: 26px;
// margin-left: -42px;
background-color: #EAD143;
}
}
}
} }
} }
@ -450,7 +491,7 @@ div.attachmentQueueStatus {
border-width: 0 $arrow-size $arrow-size $arrow-size; border-width: 0 $arrow-size $arrow-size $arrow-size;
border-color: transparent transparent black transparent; border-color: transparent transparent black transparent;
position: fixed; position: fixed;
right: 70px; right: 66px;
top: calc(49px - #{$arrow-size}); top: calc(49px - #{$arrow-size});
} }
@ -609,6 +650,208 @@ div.attachmentQueueStatus {
} }
} }
//=============================================================================
$arrow-size: 8px;
div.certificateQueueStatus {
position: fixed;
top: calc(48px - #{$arrow-size});
right: 0;
padding: 0;
color: white;
z-index: 10;
height: calc(100% - 48px);
pointer-events: none;
.arrow {
width: 0;
height: 0;
border-style: solid;
border-width: 0 $arrow-size $arrow-size $arrow-size;
border-color: transparent transparent black transparent;
position: fixed;
right: 110px;
top: calc(49px - #{$arrow-size});
}
&.closed {
display: none;
visibility: hidden;
}
p {
padding: 1em;
}
ul {
pointer-events: all;
max-height: 100%;
overflow-y: auto;
overflow-x: hidden;
white-space: nowrap;
background: black;
margin-top: $arrow-size;
padding: 0;
box-shadow: 0px 2px 5px #888888;
li {
padding: 0 0 0 1em;;
border-bottom: 1px solid white;
span {
display: inline-block;
vertical-align: middle;
height: 40px;
line-height: 40px;
}
&.requested {
.icon {
color: #999;
}
.close {
// display: none;
visibility: hidden;
}
}
&.published {
.icon {
color: #EAD143;
}
}
.icon {
@include icon-font();
color: white;
width: 30px;
}
.name {
width: 250px;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
}
.status {
width: 150px;
text-align: right;
.statusString {
font-size: 14px;
}
// .processIcon {
// margin-left: 1em;
// font-size: 15pt;
// }
}
.close {
a {
@include icon-font();
display: inline-block;
width: 50px;
text-align: center;
letter-spacing: 1px;
font-size: 20px;
@include userSelectNone();
}
a:hover {
color: lightgray;
cursor: pointer;
}
}
// .progress {
// width: 50px;
// height: 30px;
// text-align: center;
//
// @include userSelectNone();
// }
&:last-child {
border-bottom: 0;
}
}
}
/*
.radialProgressIndicator {
height: 25px;
.background {
fill: white;
}
.progress {
fill: $clipperz-orange;
}
}
*/
}
.narrow {
.certificateQueueStatus {
width:100%;
ul {
white-space: inherit;
li {
padding-top: .2em;
padding-bottom: .2em;
span {
height: 25px;
line-height: 30px;
}
.name {
width: 225px;
}
.status {
padding-left: 30px;
text-align: left;
width: calc(100% - 100px);
line-height: 20px;
font-size: .8em;
.processIcon {
margin-left: 0.5em;
}
}
.close {
height: inherit;
line-height: inherit;
float: right;
display: block;
margin-top: -5px;
}
// .progress {
// padding-left: 18px;
// margin-top: -24px;
// }
}
}
}
}
//=============================================================================
div.cardContent { div.cardContent {
// @include flex(flex-grow); // ??? // @include flex(flex-grow); // ???

View File

@ -116,46 +116,6 @@ div.overlay {
} }
} }
// http://37signals.com/svn/posts/2577-loading-spinner-animation-using-css-and-webkit
div.spinner {
position: relative;
width: 100px;
height: 100px;
left: 50%;
top: 40%;
margin-left: -50px;
margin-top: -50px;
// display: inline-block;
display: block;
div {
width: 12%;
height: 26%;
background: #ffffff;
position: absolute;
left: 44.5%;
top: 37%;
opacity: 0;
@include animation(overlay-spin, 1s, linear, infinite);
@include border-radius(50px);
@include box-shadow(0, 0, 3px, rgba(0,0,0,0.2));
}
div.bar01 {@include transform( 0deg, 0, -142%); @include animation-delay(-0.00000s);}
div.bar02 {@include transform( 30deg, 0, -142%); @include animation-delay(-0.91670s);}
div.bar03 {@include transform( 60deg, 0, -142%); @include animation-delay(-0.83300s);}
div.bar04 {@include transform( 90deg, 0, -142%); @include animation-delay(-0.75000s);}
div.bar05 {@include transform(120deg, 0, -142%); @include animation-delay(-0.66700s);}
div.bar06 {@include transform(150deg, 0, -142%); @include animation-delay(-0.58330s);}
div.bar07 {@include transform(180deg, 0, -142%); @include animation-delay(-0.50000s);}
div.bar08 {@include transform(210deg, 0, -142%); @include animation-delay(-0.41667s);}
div.bar09 {@include transform(240deg, 0, -142%); @include animation-delay(-0.33300s);}
div.bar10 {@include transform(270deg, 0, -142%); @include animation-delay(-0.25000s);}
div.bar11 {@include transform(300deg, 0, -142%); @include animation-delay(-0.16670s);}
div.bar12 {@include transform(330deg, 0, -142%); @include animation-delay(-0.08330s);}
}
&.spinnerOnly { &.spinnerOnly {
.spinner { .spinner {
@ -183,6 +143,46 @@ div.overlay {
} }
} }
// http://37signals.com/svn/posts/2577-loading-spinner-animation-using-css-and-webkit
div.spinner {
position: relative;
width: 100px;
height: 100px;
left: 50%;
top: 40%;
margin-left: -50px;
margin-top: -50px;
display: block;
div {
width: 12%;
height: 26%;
background: #ffffff;
position: absolute;
left: 44.5%;
top: 37%;
opacity: 0;
@include animation(overlay-spin, 1s, linear, infinite);
@include border-radius(50px);
@include box-shadow(0, 0, 3px, rgba(0,0,0,0.2));
}
div.bar01 {@include transform( 0deg, 0, -142%); @include animation-delay(-0.00000s);}
div.bar02 {@include transform( 30deg, 0, -142%); @include animation-delay(-0.91670s);}
div.bar03 {@include transform( 60deg, 0, -142%); @include animation-delay(-0.83300s);}
div.bar04 {@include transform( 90deg, 0, -142%); @include animation-delay(-0.75000s);}
div.bar05 {@include transform(120deg, 0, -142%); @include animation-delay(-0.66700s);}
div.bar06 {@include transform(150deg, 0, -142%); @include animation-delay(-0.58330s);}
div.bar07 {@include transform(180deg, 0, -142%); @include animation-delay(-0.50000s);}
div.bar08 {@include transform(210deg, 0, -142%); @include animation-delay(-0.41667s);}
div.bar09 {@include transform(240deg, 0, -142%); @include animation-delay(-0.33300s);}
div.bar10 {@include transform(270deg, 0, -142%); @include animation-delay(-0.25000s);}
div.bar11 {@include transform(300deg, 0, -142%); @include animation-delay(-0.16670s);}
div.bar12 {@include transform(330deg, 0, -142%); @include animation-delay(-0.08330s);}
}
//======================================================== //========================================================
@include keyframes(overlay-spin) { @include keyframes(overlay-spin) {

File diff suppressed because one or more lines are too long

View File

@ -21,38 +21,47 @@ refer to http://www.clipperz.com.
*/ */
div.dialog { div.dialogBox {
@include box-shadow(0px, 2px, 5px, rgba(50, 50, 50, 0.75)); div.dialog {
@include border-radius(8px); @include box-shadow(0px, 2px, 5px, rgba(50, 50, 50, 0.75));
@include border-radius(8px);
max-width: 70%; max-width: 70%;
background-color: white; background-color: white;
padding: 30px; padding: 30px;
box-shadow: 4px 4px 6px 5px rgba(0,0,0, 0.3); box-shadow: 4px 4px 6px 5px rgba(0,0,0, 0.3);
h3.message { h3.message {
font-size: 18pt; font-size: 18pt;
font-weight: bold; font-weight: bold;
padding-bottom: 20px; padding-bottom: 20px;
white-space: pre-wrap; white-space: pre-wrap;
word-wrap: break-word; word-wrap: break-word;
} }
div.answers { div.answers {
div.button { div.button {
@include border-radius(4); @include border-radius(4);
// border: 1px solid black; // border: 1px solid black;
margin-left: 10px; margin-left: 10px;
font-size: 16pt; font-size: 16pt;
padding: 15px 25px; padding: 15px 25px;
background-color: #ddd; background-color: #ddd;
&.isDefault { &.isDefault {
font-weight: bold; font-weight: bold;
color: white; color: white;
background-color: #666; background-color: #666;
}
&.disabled {
cursor: default;
color: #aaa;
background-color: #ddd;
font-weight: normal;
}
} }
} }
} }
} }

View File

@ -0,0 +1,71 @@
/*
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/.
*/
#errorPage {
header {
background-color: $clipperz-orange;
color: white;
height: 48px;
text-align: center;
@include icon-font();
h2 {
font-size: 24pt;
padding-top: 8px;
}
}
.error-box {
@include border-radius(16px);
background-color: #000;
color: white;
width: 300px;
height: 300px;
margin-left: auto;
margin-right: auto;
margin-top: 50px;
div {
padding: 20px;
padding-bottom: 0px;
p {
font-size: 20pt;
line-height: 1.5em;
text-align: center;
padding-bottom: 8px;
}
&.error-message {
padding-top: 0px;
p {
font-size: 14pt;
color: #333;
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More