-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathescrow2.jsx.exp
170 lines (139 loc) · 5.29 KB
/
escrow2.jsx.exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/* Lexon-generated Javascript
code: Escrow
file: escrow2.lex
compiler: lexon 0.3 alpha 93 U
grammar: 0.2.20 / subset 0.3.8 alpha 79 - English / Reyes
backend: javascript 0.3.93 U
target: node 14.1+
parameters: --javascript --feedback --log --chaining --signatures --persistence --comment
*/
var fs = require('fs');
var crypto = require('crypto');
var serialize = require('serialize-javascript');
var prompt = require('prompt-sync')();
var last_caller;
var last_passphrase;
/**
**
** Main Escrow contract system
**
**/
/** LEX Escrow.
*
* "Payer" is a person.
* "Payee" is A person.
* "Arbiter" is a person.
* "Fee" is aN amount.
*
* The Payer pays an amount into escrow, appoints the Payee, appoints the Arbiter, and fixes the Fee.
**/
module.exports = class Escrow {
constructor(payer, amount, payee, arbiter, fee) {
let main = this;
/* object members: skip for restoring serialized object */
if(typeof payer !== 'undefined') {
this._escrow = 0;
this.payer = payer;
this.payee = payee;
this.arbiter = arbiter;
this.fee = fee;
this.logname = 'log';
/* start log - overwrites previous by same name */
fs.writeFileSync(this.logname, "Lexon log " + (new Date).toLocaleString('en-US') + "\n", ()=>{});
this._pay(caller, this.payer, 'escrow', amount);
this.log(payer, "✓ Payee appointed");
this.log(payer, "✓ Arbiter appointed");
this.log(payer, "✓ Fee fixed");
}
/* restore object from file - must be below class definition */
if(typeof payer === 'undefined') {
console.log("> restore from file 'state'");
var data = fs.readFileSync('state', ()=>{});
var live = eval('(' + data + ')');
Object.assign(this, live);
}
}
/* Pay Out clause */
/*
* CLAUSE: Pay Out.
* The Arbiter may pay from escrow the Fee to themselves, and afterwards pay the remainder of the escrow to the Payee.
*/
pay_out(caller) {
if(caller == this.arbiter) {
this._pay(caller, 'escrow', this.arbiter, this.fee);
this._pay(caller, 'escrow', this.payee, this._escrow);
} else {
return 'not permitted.';
}
return 'done.';
}
/* Pay Back clause */
/*
* CLAUSE: Pay Back.
* The Arbiter may pay from escrow the Fee to themselves, and afterwards return the remainder of the escrow to the Payer.
*/
pay_back(caller) {
if(caller == this.arbiter) {
this._pay(caller, 'escrow', this.arbiter, this.fee);
this._pay(caller, 'escrow', this.payer, this._escrow);
} else {
return 'not permitted.';
}
return 'done.';
}
/* built-in convenience function to view state change log. */
history() {
fs.readFile(this.logname, (e,d)=>{console.log(d.toString())});
}
/* built-in serialization and storage of entire contract system state. */
persist() {
console.log('> persisting');
var data = serialize(this, {space: 4});
fs.writeFileSync('state', data, ()=>{});
}
/* re-instate entire contract system from serialized file store */
static load() {
return new Escrow();
}
/* built-in logging of state changes. */
log(caller, msg) {
console.log(msg);
let stamp = (new Date()).toLocaleString('en-US');
var entry = `⌽ ${stamp} ✦ ${caller} ${msg}`;
var passphrase = this.sync_passphrase(caller);
var pem = fs.readFileSync(caller + '.key');
var key = pem.toString('ascii');
var sign = crypto.createSign('RSA-SHA256');
sign.update(entry);
var sig = sign.sign({ key: key, passphrase: passphrase }, 'hex');
fs.appendFileSync(this.logname, `${entry} ❈ ${sig}\n`);
let pay = fs.readFileSync(this.logname);
let hash = crypto.createHash('sha256').update(pay);
fs.appendFileSync(this.logname, '⧉ ' + hash.digest('hex').substr(0, 12) + " ");
}
/* built-in password query for private key file, with cache. */
sync_passphrase(caller) {
if(!caller) process.exit('no caller information');
if(caller == last_caller) return last_passphrase;
last_caller = caller;
return last_passphrase = prompt('enter pass phrase for ' + caller + ': ', {echo: ''});
}
/* built-in convenience function to create keys for users. */
static create_key(name, passphrase) {
const { publicKey, privateKey } =
crypto.generateKeyPairSync('rsa',
{ modulusLength: 2048,
publicKeyEncoding: { type: 'spki', format: 'pem' },
privateKeyEncoding: { type: 'pkcs8', format: 'pem', cipher: 'aes-256-cbc', passphrase: passphrase }});
fs.writeFileSync(name+'.key', privateKey);
fs.writeFileSync(name+'.pub', publicKey);
return true;
}
/* built-in pay message */
_pay(caller, from, to, amount) {
this.log(caller, `➠ system message: pay ${amount} from ${from} to ${to}.`);
if(from == 'escrow') main._escrow -= amount;
if(to == 'escrow') main._escrow += amount;
}
}
/* end */