-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclass_addressGenerator.html
413 lines (395 loc) · 23.4 KB
/
class_addressGenerator.html
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>class_addressGenerator.html</title>
<style type="text/css">
.end-element { fill : #FFCCFF; }
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/raphael/2.3.0/raphael.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/flowchart/1.17.1/flowchart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.1/js/bootstrap.bundle.min.js"></script>
<!-- <script src="../release/flowchart.min.js"></script> -->
<script>
window.onload = function () {
var btn = document.getElementById("run"),
cd = document.getElementById("code"),
chart;
(btn.onclick = function () {
var code = cd.value;
if (chart) {
chart.clean();
}
chart = flowchart.parse(code);
chart.drawSVG('canvas', {
'x': 0,
'y': 0,
'line-width': 3,
//'maxWidth': 15,//ensures the flowcharts fits within a certain width
'line-length': 50,
'text-margin': 10,
'font-size': 14,
'font': 'normal',
'font-family': 'Helvetica',
'font-weight': 'normal',
'font-color': 'black',
'line-color': 'black',
'element-color': 'black',
'fill': 'white',
'yes-text': 'yes',
'no-text': 'no',
'arrow-end': 'block',
'scale': 1,
'symbols': {
'start': {
'font-size': 14,
'font-color': 'yellow',
'element-color': 'blue',
'fill': 'green',
'class': 'start-element'
},
'inputoutput': {
'font-color': 'black',
'element-color': 'black',
'fill': 'bisque'
},
'operation': {
'font-color': 'black',
'element-color': 'black',
'fill': 'linen'
},
'subroutine': {
'font-color': 'black',
'element-color': 'blue',
'fill': 'lightgreen'
},
'condition': {
'font-color': 'red',
'element-color': 'black',
'fill': 'yellow'
},
'end':{
'font-size': 20,
'class': 'end-element'
}
},
'flowstate' : {
//'past' : { 'fill' : '#CCCCCC', 'font-size' : 12},
//'current' : {'fill' : 'yellow', 'font-color' : 'red', 'font-weight' : 'bold'},
//'future' : { 'fill' : '#FFFF99'},
'request' : { 'fill' : 'blue'},
'invalid': {'fill' : '#444444'},
'approved' : { 'fill' : '#58C4A3', 'font-size' : 12, 'yes-text' : 'APPROVED', 'no-text' : 'n/a' },
'rejected' : { 'fill' : '#C45879', 'font-size' : 12, 'yes-text' : 'n/a', 'no-text' : 'REJECTED' }
}
});
//create base64 encoding of SVG to generate download link for title(without html or htm).SVG
var currentCanvasDIV = document.getElementById('canvas')
var currentDrawSVG = currentCanvasDIV.innerHTML.replaceAll('ë','e');
const OUTsvgBASE64 = btoa(currentDrawSVG)
doctitle = document.title.replace('.html','');
doctitle = doctitle.replace('.htm','');
var currentCanvasDIV = document.getElementById('canvas')
var currentDrawSVG = currentCanvasDIV.innerHTML.replaceAll('ë','e');
svgSource = currentDrawSVG
svgXML = currentDrawSVG;
// Use SVG Height and Width from the SVG XML to set canvas size
svgXMLsubstringHeight = svgXML.substring(svgXML.indexOf('height='), svgXML.indexOf('version='));
svgXMLsubstringWidth = svgXML.substring(svgXML.indexOf('width='), svgXML.indexOf('xmlns='));
HeightValue = svgXMLsubstringHeight.substring(svgXMLsubstringHeight.indexOf('"')+1,svgXMLsubstringHeight.lastIndexOf('"'));
WidthValue = svgXMLsubstringWidth.substring(svgXMLsubstringWidth.indexOf('"')+1,svgXMLsubstringWidth.lastIndexOf('"'));
HeightValueInt = Math.round(HeightValue)
WidthValueInt = Math.round(WidthValue)
// setup input for base64SvgToBase64Png
let svgSrc = "data:image/svg+xml;base64,"+OUTsvgBASE64;
var pngBase
imageUtil.base64SvgToBase64Png(svgSrc, WidthValueInt, HeightValueInt).then(pngSrc => {
pngBase = pngSrc
// output download link for base64 PNG converted on download from base64
var pngOutHtml = `<a href="${pngBase}" download="${doctitle}.png">PNG - Click here to download current rendered flowchart as ${doctitle}.png</a>`
document.getElementById("pngbase64").innerHTML=pngOutHtml;
});
// output download link for base64 SVG converted on download from base64
var svgOutHtml = `<a href="data:image/svg+xml;base64,${OUTsvgBASE64}" download=${doctitle}.svg>SVG - Click here to download current rendered flowchart as ${doctitle}.svg</a> `
document.getElementById("svgbase64").innerHTML=svgOutHtml;
})();
};
// derived from https://stackoverflow.com/a/64800570
// we need to use web browser canvas to generate a image. In this case png
let imageUtil = {};
/**
* converts a base64 encoded data url SVG image to a PNG image
* @param originalBase64 data url of svg image
* @param width target width in pixel of PNG image
* @param secondTry used internally to prevent endless recursion
* @return {Promise<unknown>} resolves to png data url of the image
*/
imageUtil.base64SvgToBase64Png = function (originalBase64, width, height, secondTry) {
return new Promise(resolve => {
let img = document.createElement('img');
img.onload = function () {
if (!secondTry && (img.naturalWidth === 0 || img.naturalHeight === 0)) {
let svgDoc = base64ToSvgDocument(originalBase64);
let fixedDoc = fixSvgDocumentFF(svgDoc);
return imageUtil.base64SvgToBase64Png(svgDocumentToBase64(fixedDoc), width, height, true).then(result => {
resolve(result);
});
}
//document.body.appendChild(img);
let canvas2 = document.createElement("canvas");
//document.body.removeChild(img);
canvas2.width = width;
canvas2.height = height;
let ctx = canvas2.getContext("2d");
ctx.drawImage(img, 0, 0, canvas2.width, canvas2.height);
try {
let data = canvas2.toDataURL('image/png');
resolve(data);
} catch (e) {
resolve(null);
}
};
img.src = originalBase64;
});
}
//needed because Firefox doesn't correctly handle SVG with size = 0, see https://bugzilla.mozilla.org/show_bug.cgi?id=700533
function fixSvgDocumentFF(svgDocument) {
try {
let widthInt = parseInt(svgDocument.documentElement.width.baseVal.value) || 500;
let heightInt = parseInt(svgDocument.documentElement.height.baseVal.value) || 500;
svgDocument.documentElement.width.baseVal.newValueSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PX, widthInt);
svgDocument.documentElement.height.baseVal.newValueSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PX, heightInt);
return svgDocument;
} catch (e) {
return svgDocument;
}
}
function svgDocumentToBase64(svgDocument) {
try {
let base64EncodedSVG = btoa(new XMLSerializer().serializeToString(svgDocument));
return 'data:image/svg+xml;base64,' + base64EncodedSVG;
} catch (e) {
return null;
}
}
function base64ToSvgDocument(base64) {
let svg = atob(base64.substring(base64.indexOf('base64,') + 7));
svg = svg.substring(svg.indexOf('<svg'));
let parser = new DOMParser();
return parser.parseFromString(svg, "image/svg+xml");
}
</script>
<script>
function HelpText() {
var x = document.getElementById("HelpTextBlock");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
</script>
</head>
<body>
<div><textarea id="code" style="width: 100%;" rows="11">op2=>operation: '\nA thread for creating addresses\n'
op4=>operation: import time
op6=>operation: from binascii import hexlify
op8=>operation: from six.moves import configparser, queue
op10=>operation: import defaults
op12=>operation: import highlevelcrypto
op14=>operation: import queues
op16=>operation: import shared
op18=>operation: import state
op20=>operation: from addresses import decodeAddress, encodeAddress, encodeVarint
op22=>operation: from bmconfigparser import config
op24=>operation: from network import StoppableThread
op26=>operation: from tr import _translate
op28=>operation: class AddressGeneratorException(Exception):
'Generic AddressGenerator exception'
pass
op30=>operation: class addressGenerator(StoppableThread):
'A thread for creating addresses'
name = 'addressGenerator'
def stopThread(self):
"Tell the thread to stop putting a special command to it's queue"
try:
queues.addressGeneratorQueue.put(('stopThread', 'data'))
except queue.Full:
self.logger.error('addressGeneratorQueue is Full')
super(addressGenerator, self).stopThread()
def run(self):
'\n Process the requests for addresses generation\n from `.queues.addressGeneratorQueue`\n '
while (state.shutdown == 0):
queueValue = queues.addressGeneratorQueue.get()
nonceTrialsPerByte = 0
payloadLengthExtraBytes = 0
live = True
if (queueValue[0] == 'createChan'):
(command, addressVersionNumber, streamNumber, label, deterministicPassphrase, live) = queueValue
eighteenByteRipe = False
numberOfAddressesToMake = 1
numberOfNullBytesDemandedOnFrontOfRipeHash = 1
elif (queueValue[0] == 'joinChan'):
(command, chanAddress, label, deterministicPassphrase, live) = queueValue
eighteenByteRipe = False
addressVersionNumber = decodeAddress(chanAddress)[1]
streamNumber = decodeAddress(chanAddress)[2]
numberOfAddressesToMake = 1
numberOfNullBytesDemandedOnFrontOfRipeHash = 1
elif (len(queueValue) == 7):
(command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe) = queueValue
numberOfNullBytesDemandedOnFrontOfRipeHash = config.safeGetInt('bitmessagesettings', 'numberofnullbytesonaddress', (2 if eighteenByteRipe else 1))
elif (len(queueValue) == 9):
(command, addressVersionNumber, streamNumber, label, numberOfAddressesToMake, deterministicPassphrase, eighteenByteRipe, nonceTrialsPerByte, payloadLengthExtraBytes) = queueValue
numberOfNullBytesDemandedOnFrontOfRipeHash = config.safeGetInt('bitmessagesettings', 'numberofnullbytesonaddress', (2 if eighteenByteRipe else 1))
elif (queueValue[0] == 'stopThread'):
break
else:
self.logger.error('Programming error: A structure with the wrong number of values was passed into the addressGeneratorQueue. Here is the queueValue: %r\n', queueValue)
if ((addressVersionNumber < 3) or (addressVersionNumber > 4)):
self.logger.error('Program error: For some reason the address generator queue has been given a request to create at least one version %s address which it cannot do.\n', addressVersionNumber)
if (nonceTrialsPerByte == 0):
nonceTrialsPerByte = config.getint('bitmessagesettings', 'defaultnoncetrialsperbyte')
if (nonceTrialsPerByte < defaults.networkDefaultProofOfWorkNonceTrialsPerByte):
nonceTrialsPerByte = defaults.networkDefaultProofOfWorkNonceTrialsPerByte
if (payloadLengthExtraBytes == 0):
payloadLengthExtraBytes = config.getint('bitmessagesettings', 'defaultpayloadlengthextrabytes')
if (payloadLengthExtraBytes < defaults.networkDefaultPayloadLengthExtraBytes):
payloadLengthExtraBytes = defaults.networkDefaultPayloadLengthExtraBytes
if (command == 'createRandomAddress'):
queues.UISignalQueue.put(('updateStatusBar', _translate('MainWindow', 'Generating one new address')))
startTime = time.time()
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0
(privSigningKey, pubSigningKey) = highlevelcrypto.random_keys()
while True:
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1
(potentialPrivEncryptionKey, potentialPubEncryptionKey) = highlevelcrypto.random_keys()
ripe = highlevelcrypto.to_ripe(pubSigningKey, potentialPubEncryptionKey)
if (ripe[:numberOfNullBytesDemandedOnFrontOfRipeHash] == (b'\x00' * numberOfNullBytesDemandedOnFrontOfRipeHash)):
break
self.logger.info('Generated address with ripe digest: %s', hexlify(ripe))
try:
self.logger.info('Address generator calculated %s addresses at %s addresses per second before finding one with the correct ripe-prefix.', numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix, (numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix / (time.time() - startTime)))
except ZeroDivisionError:
pass
address = encodeAddress(addressVersionNumber, streamNumber, ripe)
privSigningKeyWIF = highlevelcrypto.encodeWalletImportFormat(privSigningKey)
privEncryptionKeyWIF = highlevelcrypto.encodeWalletImportFormat(potentialPrivEncryptionKey)
config.add_section(address)
config.set(address, 'label', label)
config.set(address, 'enabled', 'true')
config.set(address, 'decoy', 'false')
config.set(address, 'noncetrialsperbyte', str(nonceTrialsPerByte))
config.set(address, 'payloadlengthextrabytes', str(payloadLengthExtraBytes))
config.set(address, 'privsigningkey', privSigningKeyWIF.decode())
config.set(address, 'privencryptionkey', privEncryptionKeyWIF.decode())
config.save()
queues.apiAddressGeneratorReturnQueue.put(address)
queues.UISignalQueue.put(('updateStatusBar', _translate('MainWindow', 'Done generating address. Doing work necessary to broadcast it...')))
queues.UISignalQueue.put(('writeNewAddressToTable', (label, address, streamNumber)))
shared.reloadMyAddressHashes()
if (addressVersionNumber == 3):
queues.workerQueue.put(('sendOutOrStoreMyV3Pubkey', ripe))
elif (addressVersionNumber == 4):
queues.workerQueue.put(('sendOutOrStoreMyV4Pubkey', address))
elif (command in ('createDeterministicAddresses', 'createChan', 'getDeterministicAddress', 'joinChan')):
if (not deterministicPassphrase):
self.logger.warning('You are creating deterministic address(es) using a blank passphrase. Bitmessage will do it but it is rather stupid.')
if (command == 'createDeterministicAddresses'):
queues.UISignalQueue.put(('updateStatusBar', _translate('MainWindow', 'Generating %1 new addresses.').arg(str(numberOfAddressesToMake))))
signingKeyNonce = 0
encryptionKeyNonce = 1
listOfNewAddressesToSendOutThroughTheAPI = []
for _ in range(numberOfAddressesToMake):
startTime = time.time()
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix = 0
while True:
numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix += 1
(potentialPrivSigningKey, potentialPubSigningKey) = highlevelcrypto.deterministic_keys(deterministicPassphrase, encodeVarint(signingKeyNonce))
(potentialPrivEncryptionKey, potentialPubEncryptionKey) = highlevelcrypto.deterministic_keys(deterministicPassphrase, encodeVarint(encryptionKeyNonce))
signingKeyNonce += 2
encryptionKeyNonce += 2
ripe = highlevelcrypto.to_ripe(potentialPubSigningKey, potentialPubEncryptionKey)
if (ripe[:numberOfNullBytesDemandedOnFrontOfRipeHash] == (b'\x00' * numberOfNullBytesDemandedOnFrontOfRipeHash)):
break
self.logger.info('Generated address with ripe digest: %s', hexlify(ripe))
try:
self.logger.info('Address generator calculated %s addresses at %s addresses per second before finding one with the correct ripe-prefix.', numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix, (numberOfAddressesWeHadToMakeBeforeWeFoundOneWithTheCorrectRipePrefix / (time.time() - startTime)))
except ZeroDivisionError:
pass
address = encodeAddress(addressVersionNumber, streamNumber, ripe)
saveAddressToDisk = True
if (command == 'joinChan'):
if (address != chanAddress):
listOfNewAddressesToSendOutThroughTheAPI.append('chan name does not match address')
saveAddressToDisk = False
if (command == 'getDeterministicAddress'):
saveAddressToDisk = False
if (saveAddressToDisk and live):
privSigningKeyWIF = highlevelcrypto.encodeWalletImportFormat(potentialPrivSigningKey)
privEncryptionKeyWIF = highlevelcrypto.encodeWalletImportFormat(potentialPrivEncryptionKey)
try:
config.add_section(address)
addressAlreadyExists = False
except configparser.DuplicateSectionError:
addressAlreadyExists = True
if addressAlreadyExists:
self.logger.info('%s already exists. Not adding it again.', address)
queues.UISignalQueue.put(('updateStatusBar', _translate('MainWindow', "%1 is already in 'Your Identities'. Not adding it again.").arg(address)))
else:
self.logger.debug('label: %s', label)
config.set(address, 'label', label)
config.set(address, 'enabled', 'true')
config.set(address, 'decoy', 'false')
if (command in ('createChan', 'joinChan')):
config.set(address, 'chan', 'true')
config.set(address, 'noncetrialsperbyte', str(nonceTrialsPerByte))
config.set(address, 'payloadlengthextrabytes', str(payloadLengthExtraBytes))
config.set(address, 'privsigningkey', privSigningKeyWIF.decode())
config.set(address, 'privencryptionkey', privEncryptionKeyWIF.decode())
config.save()
queues.UISignalQueue.put(('writeNewAddressToTable', (label, address, str(streamNumber))))
listOfNewAddressesToSendOutThroughTheAPI.append(address)
shared.myECCryptorObjects[ripe] = highlevelcrypto.makeCryptor(hexlify(potentialPrivEncryptionKey))
shared.myAddressesByHash[ripe] = address
tag = highlevelcrypto.double_sha512(((encodeVarint(addressVersionNumber) + encodeVarint(streamNumber)) + ripe))[32:]
shared.myAddressesByTag[tag] = address
if (addressVersionNumber == 3):
queues.workerQueue.put(('sendOutOrStoreMyV3Pubkey', ripe))
elif (addressVersionNumber == 4):
queues.workerQueue.put(('sendOutOrStoreMyV4Pubkey', address))
queues.UISignalQueue.put(('updateStatusBar', _translate('MainWindow', 'Done generating address')))
elif (saveAddressToDisk and (not live) and (not config.has_section(address))):
listOfNewAddressesToSendOutThroughTheAPI.append(address)
if (command in ('createDeterministicAddresses', 'createChan', 'joinChan')):
queues.apiAddressGeneratorReturnQueue.put(listOfNewAddressesToSendOutThroughTheAPI)
elif (command == 'getDeterministicAddress'):
queues.apiAddressGeneratorReturnQueue.put(address)
else:
raise AddressGeneratorException((('Error in the addressGenerator thread. Thread was' + ' given a command it could not understand: ') + command))
queues.addressGeneratorQueue.task_done()
op2->op4
op4->op6
op6->op8
op8->op10
op10->op12
op12->op14
op14->op16
op16->op18
op18->op20
op20->op22
op22->op24
op24->op26
op26->op28
op28->op30
</textarea></div>
<div><button id="run" type="button">Run</button> <button onclick="HelpText()">Format Help</button></div>
<div id="HelpTextBlock" style="display:none"><br/>Conditions can also be redirected like cond(yes, bottom) or cond(yes, right)
... and the other symbols too... like sub1(right)<br/>
You can also tweak the <b>diagram.drawSVG('diagram', {});</b> script in this file for more changes<br/>
This is based on <a href="https://github.com/adrai/flowchart.js">flowchart.js on github</a> and <a href="http://flowchart.js.org">http://flowchart.js.org</a> more documentation can be found over there.
</div><br/><div id="svgbase64"></div>
<div id="pngbase64"></div>
<div id="canvas"></div>
</body>
</html>