Skip to content
Snippets Groups Projects
Commit e44e0263 authored by Cédric Moreau's avatar Cédric Moreau
Browse files

Add accounts export

parent 7baf67c8
No related branches found
No related tags found
No related merge requests found
......@@ -34,4 +34,5 @@ module.exports = () => {
homeControllers.controller('KeyController', require('./controllers/main/settings/tabs/KeyController'));
homeControllers.controller('GraphsController', require('./controllers/main/graphs/GraphsController'));
homeControllers.controller('GraphsBlockchainController', require('./controllers/main/graphs/GraphsBlockchainController'));
homeControllers.controller('GraphsAccountsController', require('./controllers/main/graphs/GraphsAccountsController'));
};
"use strict";
var co = require('co');
module.exports = ($scope, $state, $timeout, summary, bmapi, BMA, UIUtils, Graph) => {
$scope.pubkey_preview = summary.pubkey;
$scope.updateGraphs = () => {
return co(function *() {
let series = yield bmapi.utils.accounts.js($scope.pubkey_preview);
let fseries = series.slice(0,6).map((serie) => {
return {
type: 'line',
name: serie.name,
data: serie.data
};
});
Graph.accountsGraph("#accountsGraph", 0, fseries);
});
};
$scope.download = () => {
return co(function *() {
let csv = yield bmapi.utils.accounts.csv();
window.open(encodeURI("data:text/csv;charset=utf-8," + csv));
});
};
return co(function *() {
yield $scope.updateGraphs();
$scope.$apply();
});
};
{
"top.menu.overview": "Home",
"top.menu.graphs": "Graphs",
"top.menu.data": "Explore",
"top.menu.settings": "Settings",
"top.menu.logs": "Logs",
"general.server.started": "Server started",
......@@ -138,8 +138,19 @@
"settings.data.reset.experimental": "This functionality is still considered experimental. If you encounters strange behaviors, please stop the software and reset manually your node by removing all the files BUT conf.json under ~/.config/ucoin/ucoin_default, and restart the software.",
"graphs.tabs.blockchain": "Blockchain",
"graphs.tabs.currency": "Currency",
"graphs.tabs.accounts": "Accounts",
"graphs.blockchain.range": "Graphs for the last X blocks: (please choose X value)",
"graphs.blockchain.with.time": "Time variations graph",
"graphs.blockchain.with.speed": "Writing speed graph",
"graphs.blockchain.with.difficulty": "Difficulty graph"
"graphs.blockchain.with.difficulty": "Difficulty graph",
"graphs.accounts.title": "Accounts",
"graphs.accounts.message": "Here are few utilities to visualize account evolution over time, and download a dump of all acounts at current time.",
"graphs.accounts.one_on_c": "1/c curve",
"graphs.accounts.m_on_n": "M/N curve",
"graphs.accounts.with_members": "Member accounts",
"graphs.accounts.with_non_members": "Libre accounts",
"graphs.accounts.chart.curves": "Accounts evolution",
"graphs.accounts.chart.pie": "Money share",
"graphs.accounts.generate.button": "Generate the graph",
"graphs.accounts.full_csv.button": "Save full accounts .csv file"
}
......@@ -197,6 +197,18 @@ module.exports = (app) => {
controller: 'GraphsController'
}).
state('main.graphs.accounts', {
url: '/accounts',
resolve: {
summary: (BMA) => BMA.webmin.summary(),
bmapi: (BMA, summary) => co(function *() {
return BMA.instance(summary.host);
})
},
template: require('views/main/graphs/accounts'),
controller: 'GraphsAccountsController'
}).
state('main.graphs.blockchain', {
url: '/blockchain',
template: require('views/main/graphs/blockchain'),
......
......@@ -12,7 +12,12 @@ module.exports = (angular) => {
function getResource(uri) {
return function(params) {
return $q.when(Q.Promise((resolve, reject) => {
return $q.when(httpGet(uri, params));
}
}
function httpGet(uri, params) {
return Q.Promise((resolve, reject) => {
var config = {
timeout: conf.api_timeout
}, suffix = '', pkeys = [], queryParams = null;
......@@ -36,8 +41,7 @@ module.exports = (angular) => {
console.log(data);
reject(data);
});
}));
}
});
}
function postResource(uri) {
......@@ -118,6 +122,12 @@ module.exports = (angular) => {
}
return {
utils: {
accounts: {
js: getAccountsJS((uri) => httpGet(uri)),
csv: getAccountsCSV((uri) => httpGet(uri))
}
},
webmin: {
ws: () => ws('ws://' + server + '/webmin/ws'),
summary: getResource('/webmin/summary'),
......@@ -190,4 +200,298 @@ module.exports = (angular) => {
service.instance = BMA;
return service;
});
/******
* ACCOUNTS DUMPING
*/
function getAccountsJS(getResource) {
return (pubkey) => co(function *() {
let result = yield getAccounts(getResource, pubkey);
let withUD = result.withUD;
let columns = result.columns;
let getBlock = result.getBlock;
let current = result.current;
let UDt1 = result.UDt1;
let series = ['1/c','M/N'].concat(columns).map((col) => {
return {
name: col.key || col,
data: []
};
});
for(let i = 0; i < withUD.result.blocks.length; i++) {
let bnum = withUD.result.blocks[i];
let b = yield getBlock(bnum);
let Mprev = b.monetaryMass - b.membersCount*b.dividend;
let N = b.membersCount;
let UD = b.dividend;
let values = [10,(Mprev/N)/UD].concat(columns.map((col) => (col.balances[i]/UD)));
values.forEach((v,index) => series[index].data.push(v));
}
let MonN = current.monetaryMass/current.membersCount;
let values = [10,MonN/UDt1].concat(columns.map((col) => (col.balances[withUD.result.blocks.length]/UDt1)));
values.forEach((v,index) => series[index].data.push(v));
return series;
});
}
function getAccountsCSV(getResource) {
return () => co(function *() {
let result = yield getAccounts(getResource);
let withUD = result.withUD;
let columns = result.columns;
let getBlock = result.getBlock;
let current = result.current;
let UDt1 = result.UDt1;
let csv = 'M;' + 'N;' + 'UD;' + columns.map((col) => (col.key)).join(';') + '\n';
for(let i = 0; i < withUD.result.blocks.length; i++) {
let bnum = withUD.result.blocks[i];
let b = yield getBlock(bnum);
csv += (b.monetaryMass - b.membersCount*b.dividend) + ';' + b.membersCount + ';' + b.dividend + ';' + columns.map((col) => (col.balances[i])).join(';') + '\n';
}
csv += current.monetaryMass + ';' + current.membersCount + ';' + UDt1 + ';' + columns.map((col) => (col.balances[withUD.result.blocks.length])).join(';') + '\n';
return csv;
});
}
function getAccounts(getResource, filteringPubkey) {
let backup = localStorage.getItem('accounts');
let memory = (backup && JSON.parse(backup)) || {};
return co(function*(){
let accounts = {};
let amounts = {};
let withUD = yield getWithUD();
let withTX = yield getWithTX();
let withNewcomers = yield getWithNewcomers();
let current = yield getCurrent();
let UDt1 = Math.floor(0.1 * current.monetaryMass / current.membersCount);
for(let i = 0; i < withUD.result.blocks.length; i++) {
let bnum = withUD.result.blocks[i];
let b = yield getBlock(bnum);
amounts['D' + b.number] = b.dividend;
UDt1 = Math.max(b.dividend, UDt1);
}
for(let i = 0; i < withTX.result.blocks.length; i++) {
let bnum = withTX.result.blocks[i];
let b = yield getBlock(bnum);
for (let j = 0; j < b.transactions.length; j++) {
let t = b.transactions[j];
for (let k = 0; k < t.inputs.length; k++) {
let input = t.inputs[k];
let sp = input.split(':');
let type = sp[0];
let str = sp[1];
let num = sp[2];
let amount = 0;
let pubkey;
if (type == 'D') {
amount = amounts['D' + num];
pubkey = str;
} else {
amount = amounts[input].value;
pubkey = amounts[input].pubkey;
}
accounts[pubkey] = accounts[pubkey] || { movements: [], uid: '' };
accounts[pubkey].movements.push({
type: 'TX',
amount: -amount,
block: bnum
});
}
for (let k = 0; k < t.outputs.length; k++) {
let output = t.outputs[k];
let sp = output.split(':');
let amount = parseInt(sp[0]);
let base = sp[1];
let condition = sp[2];
let pubkey = condition.match(/^SIG\((\w+)\)$/)[1];
let source = ['T', getTransactionHash(t), k].join(':');
amounts[source] = amounts[source] || {};
amounts[source].value = amount;
amounts[source].pubkey = pubkey;
accounts[pubkey] = accounts[pubkey] || { movements: [], uid: '' };
accounts[pubkey].movements.push({
type: 'TX',
amount: amount,
block: bnum
});
}
}
}
// Newcomers UD not noted
for(let i = 0; i < withNewcomers.result.blocks.length; i++) {
let bnum = withNewcomers.result.blocks[i];
// Change current UD
let b = yield getBlock(bnum);
for (let j = 0; j < b.identities.length; j++) {
let idty = b.identities[j];
let sp = idty.split(':');
let pubkey = sp[0];
let uid = sp[3];
let ud_history = yield getUDHistory(pubkey);
let uds = ud_history.history.history;
for (let l = 0; l < uds.length; l++) {
let ud = uds[l];
accounts[pubkey] = accounts[pubkey] || { movements: [], uid: uid };
accounts[pubkey].uid = accounts[pubkey].uid || uid;
accounts[pubkey].movements.push({
type: 'UD',
amount: parseInt(ud.amount),
block: ud.block_number
});
}
}
}
if (filteringPubkey) {
accounts[filteringPubkey] = accounts[filteringPubkey] || { movements: [], uid: '' };
}
let allKeys = _.keys(accounts);
let columns = [];
for (let k = 0, len = allKeys.length; k < len; k++) {
let pubkey = allKeys[k];
let balances = [];
// let uid = accounts[pubkey].uid ? ' (' + accounts[pubkey].uid + ')' : '';
// console.log('');
// console.log('Account of %s %s', pubkey, uid);
accounts[pubkey].movements = _.sortBy(accounts[pubkey].movements, (mov) => mov.block);
let sum = 0;
for(let i = 0; i < withUD.result.blocks.length; i++) {
let bnum = withUD.result.blocks[i];
let bnumPrev = withUD.result.blocks[i-1];
let b = yield getBlock(bnum);
let movs = _.filter(accounts[pubkey].movements, (mov) => {
if (i == 0) {
return false;
}
return mov.type == 'TX' && bnumPrev < mov.block && mov.block <= bnum;
});
movs.forEach((mov) => {
sum += mov.amount;
});
balances.push(sum);
// console.log('BalanceQ = %s ; UD = %s ; BalanceR = %s', sum, b.dividend, sum / b.dividend);
let dividend = _.findWhere(accounts[pubkey].movements, { block: bnum, type: 'UD' });
if (dividend) {
sum += b.dividend;
}
}
// We add the transactions after last UD
let maxBnum = withUD.result.blocks[withUD.result.blocks.length - 1];
let movs = _.filter(accounts[pubkey].movements, (mov) => mov.block > maxBnum);
movs.forEach((mov) => {
sum += mov.amount;
});
balances.push(sum);
// console.log('BalanceQ = %s ; UD = %s ; BalanceR = %s', sum, UDt1, sum / UDt1);
columns.push({
pubkey: pubkey,
key: accounts[pubkey].uid || 'pub_' + pubkey.slice(0,6),
balances: balances
})
}
if (filteringPubkey) {
console.log(columns);
columns = _.filter(columns, (col) => col.pubkey == filteringPubkey);
}
return {
UDt1: UDt1,
current: current,
getBlock: getBlock,
columns: columns,
withUD: withUD
};
})
.catch((err) => {
console.error(err.stack);
});
function getTransactionHash(json) {
return hashf(getRawTransaction(json)).toUpperCase();
}
function getRawTransaction(json) {
let raw = "";
raw += "Version: " + (json.version) + "\n";
raw += "Type: Transaction\n";
raw += "Currency: " + json.currency + "\n";
raw += "Locktime: " + json.locktime + "\n";
raw += "Issuers:\n";
(json.issuers || []).forEach(function (issuer) {
raw += issuer + '\n';
});
raw += "Inputs:\n";
(json.inputs || []).forEach(function (input) {
raw += input + '\n';
});
raw += "Unlocks:\n";
(json.unlocks || []).forEach(function (input) {
raw += input + '\n';
});
raw += "Outputs:\n";
(json.outputs || []).forEach(function (output) {
raw += output + '\n';
});
raw += "Comment: " + (json.comment || "") + "\n";
(json.signatures || []).forEach(function (signature) {
raw += signature + '\n';
});
return raw;
}
function hashf(str) {
var bitArray = sjcl.hash.sha256.hash(str);
var digest_sha256 = sjcl.codec.hex.fromBits(bitArray);
return digest_sha256;
}
function getWithUD() {
return readFromFileOrHttp('with_ud', '/blockchain/with/ud');
}
function getWithTX() {
return readFromFileOrHttp('with_tx', '/blockchain/with/tx');
}
function getWithNewcomers() {
return readFromFileOrHttp('with_newcomers', '/blockchain/with/newcomers');
}
function getBlock(number) {
return readFromFileOrHttp('block_' + number, '/blockchain/block/' + number);
}
function getUDHistory(pubkey) {
return readFromFileOrHttp('uds_' + pubkey, '/ud/history/' + pubkey);
}
function getCurrent() {
return readFromFileOrHttp('current', '/blockchain/current');
}
function readFromFileOrHttp(filename, uri) {
return co(function *() {
if (memory[filename]) {
return memory[filename];
} else {
console.log('>>>>> ' + uri);
let content = yield getResource(uri);
memory[filename] = content;
localStorage.setItem('accounts', JSON.stringify(memory));
return content;
}
});
}
}
};
......@@ -3,6 +3,71 @@ module.exports = (app) => {
app.factory('Graph', function() {
return {
accountsGraph: function speedGraphs (id, offset, series) {
$(id).highcharts({
chart: {
type: "area",
zoomType: 'x'
},
title: {
text: 'Accounts evolution'
},
subtitle: {
text: document.ontouchstart === undefined ?
'Click and drag in the plot area to zoom in' :
'Pinch the chart to zoom in'
},
xAxis: {
//categories: xValuex,
minRange: 3, // 10 blocks,
labels: {
formatter: function() {
return this.value + offset;
}
}
},
yAxis: {
//type: 'logarithmic',
minorTickInterval: 1,
title: {
text: 'Blocks per hour (logarithmic scale)'
}
},
colors: ['#ff0000', '#7cb5ec', '#000000'],
legend: {
enabled: true
},
tooltip: {
shared: true,
crosshairs: true,
formatter: blockFormatter(offset)
},
plotOptions: {
area: {
fillColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1},
stops: [
[0, Highcharts.getOptions().colors[0]],
[1, Highcharts.Color(Highcharts.getOptions().colors[0]).setOpacity(0).get('rgba')]
]
},
marker: {
radius: 2
},
lineWidth: 1,
states: {
hover: {
lineWidth: 1
}
},
threshold: null
}
},
series: series
});
},
speedGraph: function speedGraphs (id, offset, speeds, minSpeeds, maxSpeeds, getSeries) {
var xValuex = [];
for (var i = 0, len = speeds.length; i < len; i++) {
......@@ -40,7 +105,9 @@ module.exports = (app) => {
minorTickInterval: 1,
title: {
text: 'Blocks per hour (logarithmic scale)'
}
},
floor: 0,
min: 0
},
colors: ['#ff0000', '#7cb5ec', '#000000'],
legend: {
......
.container
.row
form.s12.center
.card
.card-action
i.fa.fa-suitcase.fa-5x
h1.card-title(translate="graphs.accounts.title")
p(translate="graphs.accounts.message")
//.row
// .col.s12.m2
// input#use_curves(type="radio" name="groupUse" value="curves" ng-model="use_chart")
// label(for="use_curves") {{ 'graphs.accounts.chart.curves' | translate }}
// .col.s12.m2
// input#use_pie(type="radio" name="groupUse" value="pie" ng-model="use_chart")
// label(for="use_pie") {{ 'graphs.accounts.chart.pie' | translate }}
#accountsGraph
.row
.row
.col.s12
a.btn-large.waves-effect.waves-light(ng-click="download()")
i.left.fa.fa-download
span(translate="graphs.accounts.full_csv.button")
\ No newline at end of file
......@@ -14,6 +14,9 @@ main.home-main.main-screen
.row
.col.s12
ul.tabs
li.tab.col.s6: a(href="#main.graphs.accounts")
i.fa.fa-suitcase &nbsp;
= " {{ 'graphs.tabs.accounts' | translate }}"
li.tab.col.s6: a(href="#main.graphs.blockchain")
i.fa.fa-chain &nbsp;
= " {{ 'graphs.tabs.blockchain' | translate }}"
......
......@@ -24,9 +24,9 @@ block content
i.fa.fa-2x.fa-home.left
span {{ 'top.menu.overview' | translate }}
li(ng-class="{ active: menu == 'graphs' }")
a.waves-effect.waves-light(ui-sref="main.graphs.blockchain")
i.fa.fa-2x.fa-area-chart.left
span {{ 'top.menu.graphs' | translate }}
a.waves-effect.waves-light(ui-sref="main.graphs.accounts")
i.fa.fa-2x.fa-database.left
span {{ 'top.menu.data' | translate }}
li(ng-class="{ active: menu == 'settings' }")
a.waves-effect.waves-light(ui-sref="main.settings.data")
i.fa.fa-2x.fa-gear.left
......
"use strict";function q(a){throw a;}var t=void 0,u=!1;var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return"CORRUPT: "+this.message};this.message=a},invalid:function(a){this.toString=function(){return"INVALID: "+this.message};this.message=a},bug:function(a){this.toString=function(){return"BUG: "+this.message};this.message=a},notReady:function(a){this.toString=function(){return"NOT READY: "+this.message};this.message=a}}};
"undefined"!=typeof module&&module.exports&&(module.exports=sjcl);
sjcl.cipher.aes=function(a){this.j[0][0][0]||this.D();var b,c,d,e,f=this.j[0][4],g=this.j[1];b=a.length;var h=1;4!==b&&(6!==b&&8!==b)&&q(new sjcl.exception.invalid("invalid aes key size"));this.a=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(0===a%b||8===b&&4===a%b)c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255],0===a%b&&(c=c<<8^c>>>24^h<<24,h=h<<1^283*(h>>7));d[a]=d[a-b]^c}for(b=0;a;b++,a--)c=d[b&3?a:a-4],e[b]=4>=a||4>b?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^g[3][f[c&
255]]};
sjcl.cipher.aes.prototype={encrypt:function(a){return y(this,a,0)},decrypt:function(a){return y(this,a,1)},j:[[[],[],[],[],[]],[[],[],[],[],[]]],D:function(){var a=this.j[0],b=this.j[1],c=a[4],d=b[4],e,f,g,h=[],l=[],k,n,m,p;for(e=0;0x100>e;e++)l[(h[e]=e<<1^283*(e>>7))^e]=e;for(f=g=0;!c[f];f^=k||1,g=l[g]||1){m=g^g<<1^g<<2^g<<3^g<<4;m=m>>8^m&255^99;c[f]=m;d[m]=f;n=h[e=h[k=h[f]]];p=0x1010101*n^0x10001*e^0x101*k^0x1010100*f;n=0x101*h[m]^0x1010100*m;for(e=0;4>e;e++)a[e][f]=n=n<<24^n>>>8,b[e][m]=p=p<<24^p>>>8}for(e=
0;5>e;e++)a[e]=a[e].slice(0),b[e]=b[e].slice(0)}};
function y(a,b,c){4!==b.length&&q(new sjcl.exception.invalid("invalid aes block size"));var d=a.a[c],e=b[0]^d[0],f=b[c?3:1]^d[1],g=b[2]^d[2];b=b[c?1:3]^d[3];var h,l,k,n=d.length/4-2,m,p=4,s=[0,0,0,0];h=a.j[c];a=h[0];var r=h[1],v=h[2],w=h[3],x=h[4];for(m=0;m<n;m++)h=a[e>>>24]^r[f>>16&255]^v[g>>8&255]^w[b&255]^d[p],l=a[f>>>24]^r[g>>16&255]^v[b>>8&255]^w[e&255]^d[p+1],k=a[g>>>24]^r[b>>16&255]^v[e>>8&255]^w[f&255]^d[p+2],b=a[b>>>24]^r[e>>16&255]^v[f>>8&255]^w[g&255]^d[p+3],p+=4,e=h,f=l,g=k;for(m=0;4>
m;m++)s[c?3&-m:m]=x[e>>>24]<<24^x[f>>16&255]<<16^x[g>>8&255]<<8^x[b&255]^d[p++],h=e,e=f,f=g,g=b,b=h;return s}
sjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.O(a.slice(b/32),32-(b&31)).slice(1);return c===t?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<<c)-1},concat:function(a,b){if(0===a.length||0===b.length)return a.concat(b);var c=a[a.length-1],d=sjcl.bitArray.getPartial(c);return 32===d?a.concat(b):sjcl.bitArray.O(b,d,c|0,a.slice(0,a.length-1))},bitLength:function(a){var b=a.length;return 0===
b?0:32*(b-1)+sjcl.bitArray.getPartial(a[b-1])},clamp:function(a,b){if(32*a.length<b)return a;a=a.slice(0,Math.ceil(b/32));var c=a.length;b&=31;0<c&&b&&(a[c-1]=sjcl.bitArray.partial(b,a[c-1]&2147483648>>b-1,1));return a},partial:function(a,b,c){return 32===a?b:(c?b|0:b<<32-a)+0x10000000000*a},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return u;var c=0,d;for(d=0;d<a.length;d++)c|=a[d]^b[d];return 0===
c},O:function(a,b,c,d){var e;e=0;for(d===t&&(d=[]);32<=b;b-=32)d.push(c),c=0;if(0===b)return d.concat(a);for(e=0;e<a.length;e++)d.push(c|a[e]>>>b),c=a[e]<<32-b;e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,32<b+a?c:d.pop(),1));return d},k:function(a,b){return[a[0]^b[0],a[1]^b[1],a[2]^b[2],a[3]^b[3]]}};
sjcl.codec.utf8String={fromBits:function(a){var b="",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d<c/8;d++)0===(d&3)&&(e=a[d/4]),b+=String.fromCharCode(e>>>24),e<<=8;return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c<a.length;c++)d=d<<8|a.charCodeAt(c),3===(c&3)&&(b.push(d),d=0);c&3&&b.push(sjcl.bitArray.partial(8*(c&3),d));return b}};
sjcl.codec.hex={fromBits:function(a){var b="",c;for(c=0;c<a.length;c++)b+=((a[c]|0)+0xf00000000000).toString(16).substr(4);return b.substr(0,sjcl.bitArray.bitLength(a)/4)},toBits:function(a){var b,c=[],d;a=a.replace(/\s|0x/g,"");d=a.length;a+="00000000";for(b=0;b<a.length;b+=8)c.push(parseInt(a.substr(b,8),16)^0);return sjcl.bitArray.clamp(c,4*d)}};
sjcl.codec.base64={I:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",fromBits:function(a,b,c){var d="",e=0,f=sjcl.codec.base64.I,g=0,h=sjcl.bitArray.bitLength(a);c&&(f=f.substr(0,62)+"-_");for(c=0;6*d.length<h;)d+=f.charAt((g^a[c]>>>e)>>>26),6>e?(g=a[c]<<6-e,e+=26,c++):(g<<=6,e-=6);for(;d.length&3&&!b;)d+="=";return d},toBits:function(a,b){a=a.replace(/\s|=/g,"");var c=[],d,e=0,f=sjcl.codec.base64.I,g=0,h;b&&(f=f.substr(0,62)+"-_");for(d=0;d<a.length;d++)h=f.indexOf(a.charAt(d)),
0>h&&q(new sjcl.exception.invalid("this isn't base64!")),26<e?(e-=26,c.push(g^h>>>e),g=h<<32-e):(e+=6,g^=h<<32-e);e&56&&c.push(sjcl.bitArray.partial(e&56,g,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}};sjcl.hash.sha256=function(a){this.a[0]||this.D();a?(this.q=a.q.slice(0),this.m=a.m.slice(0),this.g=a.g):this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()};
sjcl.hash.sha256.prototype={blockSize:512,reset:function(){this.q=this.M.slice(0);this.m=[];this.g=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,c=this.m=sjcl.bitArray.concat(this.m,a);b=this.g;a=this.g=b+sjcl.bitArray.bitLength(a);for(b=512+b&-512;b<=a;b+=512)z(this,c.splice(0,16));return this},finalize:function(){var a,b=this.m,c=this.q,b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.g/
4294967296));for(b.push(this.g|0);b.length;)z(this,b.splice(0,16));this.reset();return c},M:[],a:[],D:function(){function a(a){return 0x100000000*(a-Math.floor(a))|0}var b=0,c=2,d;a:for(;64>b;c++){for(d=2;d*d<=c;d++)if(0===c%d)continue a;8>b&&(this.M[b]=a(Math.pow(c,0.5)));this.a[b]=a(Math.pow(c,1/3));b++}}};
function z(a,b){var c,d,e,f=b.slice(0),g=a.q,h=a.a,l=g[0],k=g[1],n=g[2],m=g[3],p=g[4],s=g[5],r=g[6],v=g[7];for(c=0;64>c;c++)16>c?d=f[c]:(d=f[c+1&15],e=f[c+14&15],d=f[c&15]=(d>>>7^d>>>18^d>>>3^d<<25^d<<14)+(e>>>17^e>>>19^e>>>10^e<<15^e<<13)+f[c&15]+f[c+9&15]|0),d=d+v+(p>>>6^p>>>11^p>>>25^p<<26^p<<21^p<<7)+(r^p&(s^r))+h[c],v=r,r=s,s=p,p=m+d|0,m=n,n=k,k=l,l=d+(k&n^m&(k^n))+(k>>>2^k>>>13^k>>>22^k<<30^k<<19^k<<10)|0;g[0]=g[0]+l|0;g[1]=g[1]+k|0;g[2]=g[2]+n|0;g[3]=g[3]+m|0;g[4]=g[4]+p|0;g[5]=g[5]+s|0;g[6]=
g[6]+r|0;g[7]=g[7]+v|0}
sjcl.mode.ccm={name:"ccm",encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=sjcl.bitArray,l=h.bitLength(c)/8,k=h.bitLength(g)/8;e=e||64;d=d||[];7>l&&q(new sjcl.exception.invalid("ccm: iv must be at least 7 bytes"));for(f=2;4>f&&k>>>8*f;f++);f<15-l&&(f=15-l);c=h.clamp(c,8*(15-f));b=sjcl.mode.ccm.K(a,b,c,d,e,f);g=sjcl.mode.ccm.n(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),l=f.clamp(b,h-e),k=f.bitSlice(b,
h-e),h=(h-e)/8;7>g&&q(new sjcl.exception.invalid("ccm: iv must be at least 7 bytes"));for(b=2;4>b&&h>>>8*b;b++);b<15-g&&(b=15-g);c=f.clamp(c,8*(15-b));l=sjcl.mode.ccm.n(a,l,c,k,e,b);a=sjcl.mode.ccm.K(a,l.data,c,d,e,b);f.equal(l.tag,a)||q(new sjcl.exception.corrupt("ccm: tag doesn't match"));return l.data},K:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,l=h.k;e/=8;(e%2||4>e||16<e)&&q(new sjcl.exception.invalid("ccm: invalid tag length"));(0xffffffff<d.length||0xffffffff<b.length)&&q(new sjcl.exception.bug("ccm: can't deal with 4GiB or more data"));
f=[h.partial(8,(d.length?64:0)|e-2<<2|f-1)];f=h.concat(f,c);f[3]|=h.bitLength(b)/8;f=a.encrypt(f);if(d.length){c=h.bitLength(d)/8;65279>=c?g=[h.partial(16,c)]:0xffffffff>=c&&(g=h.concat([h.partial(16,65534)],[c]));g=h.concat(g,d);for(d=0;d<g.length;d+=4)f=a.encrypt(l(f,g.slice(d,d+4).concat([0,0,0])))}for(d=0;d<b.length;d+=4)f=a.encrypt(l(f,b.slice(d,d+4).concat([0,0,0])));return h.clamp(f,8*e)},n:function(a,b,c,d,e,f){var g,h=sjcl.bitArray;g=h.k;var l=b.length,k=h.bitLength(b);c=h.concat([h.partial(8,
f-1)],c).concat([0,0,0]).slice(0,4);d=h.bitSlice(g(d,a.encrypt(c)),0,e);if(!l)return{tag:d,data:[]};for(g=0;g<l;g+=4)c[3]++,e=a.encrypt(c),b[g]^=e[0],b[g+1]^=e[1],b[g+2]^=e[2],b[g+3]^=e[3];return{tag:d,data:h.clamp(b,k)}}};
sjcl.mode.ocb2={name:"ocb2",encrypt:function(a,b,c,d,e,f){128!==sjcl.bitArray.bitLength(c)&&q(new sjcl.exception.invalid("ocb iv must be 128 bits"));var g,h=sjcl.mode.ocb2.G,l=sjcl.bitArray,k=l.k,n=[0,0,0,0];c=h(a.encrypt(c));var m,p=[];d=d||[];e=e||64;for(g=0;g+4<b.length;g+=4)m=b.slice(g,g+4),n=k(n,m),p=p.concat(k(c,a.encrypt(k(c,m)))),c=h(c);m=b.slice(g);b=l.bitLength(m);g=a.encrypt(k(c,[0,0,0,b]));m=l.clamp(k(m.concat([0,0,0]),g),b);n=k(n,k(m.concat([0,0,0]),g));n=a.encrypt(k(n,k(c,h(c))));d.length&&
(n=k(n,f?d:sjcl.mode.ocb2.pmac(a,d)));return p.concat(l.concat(m,l.clamp(n,e)))},decrypt:function(a,b,c,d,e,f){128!==sjcl.bitArray.bitLength(c)&&q(new sjcl.exception.invalid("ocb iv must be 128 bits"));e=e||64;var g=sjcl.mode.ocb2.G,h=sjcl.bitArray,l=h.k,k=[0,0,0,0],n=g(a.encrypt(c)),m,p,s=sjcl.bitArray.bitLength(b)-e,r=[];d=d||[];for(c=0;c+4<s/32;c+=4)m=l(n,a.decrypt(l(n,b.slice(c,c+4)))),k=l(k,m),r=r.concat(m),n=g(n);p=s-32*c;m=a.encrypt(l(n,[0,0,0,p]));m=l(m,h.clamp(b.slice(c),p).concat([0,0,0]));
k=l(k,m);k=a.encrypt(l(k,l(n,g(n))));d.length&&(k=l(k,f?d:sjcl.mode.ocb2.pmac(a,d)));h.equal(h.clamp(k,e),h.bitSlice(b,s))||q(new sjcl.exception.corrupt("ocb: tag doesn't match"));return r.concat(h.clamp(m,p))},pmac:function(a,b){var c,d=sjcl.mode.ocb2.G,e=sjcl.bitArray,f=e.k,g=[0,0,0,0],h=a.encrypt([0,0,0,0]),h=f(h,d(d(h)));for(c=0;c+4<b.length;c+=4)h=d(h),g=f(g,a.encrypt(f(h,b.slice(c,c+4))));c=b.slice(c);128>e.bitLength(c)&&(h=f(h,d(h)),c=e.concat(c,[-2147483648,0,0,0]));g=f(g,c);return a.encrypt(f(d(f(h,
d(h))),g))},G:function(a){return[a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^135*(a[0]>>>31)]}};
sjcl.mode.gcm={name:"gcm",encrypt:function(a,b,c,d,e){var f=b.slice(0);b=sjcl.bitArray;d=d||[];a=sjcl.mode.gcm.n(!0,a,f,d,c,e||128);return b.concat(a.data,a.tag)},decrypt:function(a,b,c,d,e){var f=b.slice(0),g=sjcl.bitArray,h=g.bitLength(f);e=e||128;d=d||[];e<=h?(b=g.bitSlice(f,h-e),f=g.bitSlice(f,0,h-e)):(b=f,f=[]);a=sjcl.mode.gcm.n(u,a,f,d,c,e);g.equal(a.tag,b)||q(new sjcl.exception.corrupt("gcm: tag doesn't match"));return a.data},U:function(a,b){var c,d,e,f,g,h=sjcl.bitArray.k;e=[0,0,0,0];f=b.slice(0);
for(c=0;128>c;c++){(d=0!==(a[Math.floor(c/32)]&1<<31-c%32))&&(e=h(e,f));g=0!==(f[3]&1);for(d=3;0<d;d--)f[d]=f[d]>>>1|(f[d-1]&1)<<31;f[0]>>>=1;g&&(f[0]^=-0x1f000000)}return e},f:function(a,b,c){var d,e=c.length;b=b.slice(0);for(d=0;d<e;d+=4)b[0]^=0xffffffff&c[d],b[1]^=0xffffffff&c[d+1],b[2]^=0xffffffff&c[d+2],b[3]^=0xffffffff&c[d+3],b=sjcl.mode.gcm.U(b,a);return b},n:function(a,b,c,d,e,f){var g,h,l,k,n,m,p,s,r=sjcl.bitArray;m=c.length;p=r.bitLength(c);s=r.bitLength(d);h=r.bitLength(e);g=b.encrypt([0,
0,0,0]);96===h?(e=e.slice(0),e=r.concat(e,[1])):(e=sjcl.mode.gcm.f(g,[0,0,0,0],e),e=sjcl.mode.gcm.f(g,e,[0,0,Math.floor(h/0x100000000),h&0xffffffff]));h=sjcl.mode.gcm.f(g,[0,0,0,0],d);n=e.slice(0);d=h.slice(0);a||(d=sjcl.mode.gcm.f(g,h,c));for(k=0;k<m;k+=4)n[3]++,l=b.encrypt(n),c[k]^=l[0],c[k+1]^=l[1],c[k+2]^=l[2],c[k+3]^=l[3];c=r.clamp(c,p);a&&(d=sjcl.mode.gcm.f(g,h,c));a=[Math.floor(s/0x100000000),s&0xffffffff,Math.floor(p/0x100000000),p&0xffffffff];d=sjcl.mode.gcm.f(g,d,a);l=b.encrypt(e);d[0]^=l[0];
d[1]^=l[1];d[2]^=l[2];d[3]^=l[3];return{tag:r.bitSlice(d,0,f),data:c}}};sjcl.misc.hmac=function(a,b){this.L=b=b||sjcl.hash.sha256;var c=[[],[]],d,e=b.prototype.blockSize/32;this.o=[new b,new b];a.length>e&&(a=b.hash(a));for(d=0;d<e;d++)c[0][d]=a[d]^909522486,c[1][d]=a[d]^1549556828;this.o[0].update(c[0]);this.o[1].update(c[1])};sjcl.misc.hmac.prototype.encrypt=sjcl.misc.hmac.prototype.mac=function(a){a=(new this.L(this.o[0])).update(a).finalize();return(new this.L(this.o[1])).update(a).finalize()};
sjcl.misc.pbkdf2=function(a,b,c,d,e){c=c||1E3;(0>d||0>c)&&q(sjcl.exception.invalid("invalid params to pbkdf2"));"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,l,k=[],n=sjcl.bitArray;for(l=1;32*k.length<(d||1);l++){e=f=a.encrypt(n.concat(b,[l]));for(g=1;g<c;g++){f=a.encrypt(f);for(h=0;h<f.length;h++)e[h]^=f[h]}k=k.concat(e)}d&&(k=n.clamp(k,d));return k};
sjcl.prng=function(a){this.b=[new sjcl.hash.sha256];this.h=[0];this.F=0;this.t={};this.C=0;this.J={};this.N=this.c=this.i=this.T=0;this.a=[0,0,0,0,0,0,0,0];this.e=[0,0,0,0];this.A=t;this.B=a;this.p=u;this.z={progress:{},seeded:{}};this.l=this.S=0;this.u=1;this.w=2;this.Q=0x10000;this.H=[0,48,64,96,128,192,0x100,384,512,768,1024];this.R=3E4;this.P=80};
sjcl.prng.prototype={randomWords:function(a,b){var c=[],d;d=this.isReady(b);var e;d===this.l&&q(new sjcl.exception.notReady("generator isn't seeded"));if(d&this.w){d=!(d&this.u);e=[];var f=0,g;this.N=e[0]=(new Date).valueOf()+this.R;for(g=0;16>g;g++)e.push(0x100000000*Math.random()|0);for(g=0;g<this.b.length&&!(e=e.concat(this.b[g].finalize()),f+=this.h[g],this.h[g]=0,!d&&this.F&1<<g);g++);this.F>=1<<this.b.length&&(this.b.push(new sjcl.hash.sha256),this.h.push(0));this.c-=f;f>this.i&&(this.i=f);this.F++;
this.a=sjcl.hash.sha256.hash(this.a.concat(e));this.A=new sjcl.cipher.aes(this.a);for(d=0;4>d&&!(this.e[d]=this.e[d]+1|0,this.e[d]);d++);}for(d=0;d<a;d+=4)0===(d+1)%this.Q&&A(this),e=B(this),c.push(e[0],e[1],e[2],e[3]);A(this);return c.slice(0,a)},setDefaultParanoia:function(a){this.B=a},addEntropy:function(a,b,c){c=c||"user";var d,e,f=(new Date).valueOf(),g=this.t[c],h=this.isReady(),l=0;d=this.J[c];d===t&&(d=this.J[c]=this.T++);g===t&&(g=this.t[c]=0);this.t[c]=(this.t[c]+1)%this.b.length;switch(typeof a){case "number":b===
t&&(b=1);this.b[g].update([d,this.C++,1,b,f,1,a|0]);break;case "object":c=Object.prototype.toString.call(a);if("[object Uint32Array]"===c){e=[];for(c=0;c<a.length;c++)e.push(a[c]);a=e}else{"[object Array]"!==c&&(l=1);for(c=0;c<a.length&&!l;c++)"number"!=typeof a[c]&&(l=1)}if(!l){if(b===t)for(c=b=0;c<a.length;c++)for(e=a[c];0<e;)b++,e>>>=1;this.b[g].update([d,this.C++,2,b,f,a.length].concat(a))}break;case "string":b===t&&(b=a.length);this.b[g].update([d,this.C++,3,b,f,a.length]);this.b[g].update(a);
break;default:l=1}l&&q(new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string"));this.h[g]+=b;this.c+=b;h===this.l&&(this.isReady()!==this.l&&C("seeded",Math.max(this.i,this.c)),C("progress",this.getProgress()))},isReady:function(a){a=this.H[a!==t?a:this.B];return this.i&&this.i>=a?this.h[0]>this.P&&(new Date).valueOf()>this.N?this.w|this.u:this.u:this.c>=a?this.w|this.l:this.l},getProgress:function(a){a=this.H[a?a:this.B];return this.i>=a?1:this.c>a?1:this.c/
a},startCollectors:function(){this.p||(window.addEventListener?(window.addEventListener("load",this.r,u),window.addEventListener("mousemove",this.s,u)):document.attachEvent?(document.attachEvent("onload",this.r),document.attachEvent("onmousemove",this.s)):q(new sjcl.exception.bug("can't attach event")),this.p=!0)},stopCollectors:function(){this.p&&(window.removeEventListener?(window.removeEventListener("load",this.r,u),window.removeEventListener("mousemove",this.s,u)):window.detachEvent&&(window.detachEvent("onload",
this.r),window.detachEvent("onmousemove",this.s)),this.p=u)},addEventListener:function(a,b){this.z[a][this.S++]=b},removeEventListener:function(a,b){var c,d,e=this.z[a],f=[];for(d in e)e.hasOwnProperty(d)&&e[d]===b&&f.push(d);for(c=0;c<f.length;c++)d=f[c],delete e[d]},s:function(a){sjcl.random.addEntropy([a.x||a.clientX||a.offsetX||0,a.y||a.clientY||a.offsetY||0],2,"mouse")},r:function(){sjcl.random.addEntropy((new Date).valueOf(),2,"loadtime")}};
function C(a,b){var c,d=sjcl.random.z[a],e=[];for(c in d)d.hasOwnProperty(c)&&e.push(d[c]);for(c=0;c<e.length;c++)e[c](b)}function A(a){a.a=B(a).concat(B(a));a.A=new sjcl.cipher.aes(a.a)}function B(a){for(var b=0;4>b&&!(a.e[b]=a.e[b]+1|0,a.e[b]);b++);return a.A.encrypt(a.e)}sjcl.random=new sjcl.prng(6);try{var D=new Uint32Array(32);crypto.getRandomValues(D);sjcl.random.addEntropy(D,1024,"crypto['getRandomValues']")}catch(E){}
sjcl.json={defaults:{v:1,iter:1E3,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},encrypt:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.d({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.d(f,c);c=f.adata;"string"===typeof f.salt&&(f.salt=sjcl.codec.base64.toBits(f.salt));"string"===typeof f.iv&&(f.iv=sjcl.codec.base64.toBits(f.iv));(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||"string"===typeof a&&100>=f.iter||64!==f.ts&&96!==f.ts&&128!==f.ts||128!==f.ks&&192!==f.ks&&0x100!==f.ks||2>f.iv.length||
4<f.iv.length)&&q(new sjcl.exception.invalid("json encrypt: invalid parameters"));"string"===typeof a&&(g=sjcl.misc.cachedPbkdf2(a,f),a=g.key.slice(0,f.ks/32),f.salt=g.salt);"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));"string"===typeof c&&(c=sjcl.codec.utf8String.toBits(c));g=new sjcl.cipher[f.cipher](a);e.d(d,f);d.key=a;f.ct=sjcl.mode[f.mode].encrypt(g,b,f.iv,c,f.ts);return e.encode(f)},decrypt:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json;b=e.d(e.d(e.d({},e.defaults),e.decode(b)),
c,!0);var f;c=b.adata;"string"===typeof b.salt&&(b.salt=sjcl.codec.base64.toBits(b.salt));"string"===typeof b.iv&&(b.iv=sjcl.codec.base64.toBits(b.iv));(!sjcl.mode[b.mode]||!sjcl.cipher[b.cipher]||"string"===typeof a&&100>=b.iter||64!==b.ts&&96!==b.ts&&128!==b.ts||128!==b.ks&&192!==b.ks&&0x100!==b.ks||!b.iv||2>b.iv.length||4<b.iv.length)&&q(new sjcl.exception.invalid("json decrypt: invalid parameters"));"string"===typeof a&&(f=sjcl.misc.cachedPbkdf2(a,b),a=f.key.slice(0,b.ks/32),b.salt=f.salt);"string"===
typeof c&&(c=sjcl.codec.utf8String.toBits(c));f=new sjcl.cipher[b.cipher](a);c=sjcl.mode[b.mode].decrypt(f,b.ct,b.iv,c,b.ts);e.d(d,b);d.key=a;return sjcl.codec.utf8String.fromBits(c)},encode:function(a){var b,c="{",d="";for(b in a)if(a.hasOwnProperty(b))switch(b.match(/^[a-z0-9]+$/i)||q(new sjcl.exception.invalid("json encode: invalid property name")),c+=d+'"'+b+'":',d=",",typeof a[b]){case "number":case "boolean":c+=a[b];break;case "string":c+='"'+escape(a[b])+'"';break;case "object":c+='"'+sjcl.codec.base64.fromBits(a[b],
0)+'"';break;default:q(new sjcl.exception.bug("json encode: unsupported type"))}return c+"}"},decode:function(a){a=a.replace(/\s/g,"");a.match(/^\{.*\}$/)||q(new sjcl.exception.invalid("json decode: this isn't json!"));a=a.replace(/^\{|\}$/g,"").split(/,/);var b={},c,d;for(c=0;c<a.length;c++)(d=a[c].match(/^(?:(["']?)([a-z][a-z0-9]*)\1):(?:(\d+)|"([a-z0-9+\/%*_.@=\-]*)")$/i))||q(new sjcl.exception.invalid("json decode: this isn't json!")),b[d[2]]=d[3]?parseInt(d[3],10):d[2].match(/^(ct|salt|iv)$/)?
sjcl.codec.base64.toBits(d[4]):unescape(d[4]);return b},d:function(a,b,c){a===t&&(a={});if(b===t)return a;for(var d in b)b.hasOwnProperty(d)&&(c&&(a[d]!==t&&a[d]!==b[d])&&q(new sjcl.exception.invalid("required parameter overridden")),a[d]=b[d]);return a},X:function(a,b){var c={},d;for(d in a)a.hasOwnProperty(d)&&a[d]!==b[d]&&(c[d]=a[d]);return c},W:function(a,b){var c={},d;for(d=0;d<b.length;d++)a[b[d]]!==t&&(c[b[d]]=a[b[d]]);return c}};sjcl.encrypt=sjcl.json.encrypt;sjcl.decrypt=sjcl.json.decrypt;
sjcl.misc.V={};sjcl.misc.cachedPbkdf2=function(a,b){var c=sjcl.misc.V,d;b=b||{};d=b.iter||1E3;c=c[a]=c[a]||{};d=c[d]=c[d]||{firstSalt:b.salt&&b.salt.length?b.salt.slice(0):sjcl.random.randomWords(2,0)};c=b.salt===t?d.firstSalt:b.salt;d[c]=d[c]||sjcl.misc.pbkdf2(a,c,b.iter);return{key:d[c].slice(0),salt:c.slice(0)}};
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment