Skip to content
This repository has been archived by the owner on Feb 15, 2024. It is now read-only.

Commit

Permalink
Version 2. Micropay.
Browse files Browse the repository at this point in the history
  • Loading branch information
n-y-z-o committed Sep 21, 2020
1 parent 30a04fe commit 924c385
Show file tree
Hide file tree
Showing 12 changed files with 580 additions and 165 deletions.
40 changes: 39 additions & 1 deletion byteBuffer.js
Expand Up @@ -5,6 +5,11 @@ class ByteBuffer {
this.array = new Uint8Array(Math.max(maximumSize, 1));
}

initializeWithArray(bytes) {
this.index = 0;
this.array = bytes;
}

putBytes(bytes) {
for (var i = 0; i < bytes.length; i++) {
this.array[this.index++] = bytes[i];
Expand All @@ -16,7 +21,6 @@ class ByteBuffer {
}

putIntegerValue(value, length) {

value = Math.floor(value);
for (var i = 0; i < length; i++) {
this.array[this.index + length - 1 - i] = value % 256;
Expand Down Expand Up @@ -45,4 +49,38 @@ class ByteBuffer {

return result;
}

readBytes(length) {
const result = new Uint8Array(length);
for (var i = 0; i < length; i++) {
result[i] = this.array[this.index++];
}

return result;
}

readByte() {
return this.array[this.index++];
}

readIntegerValue(length) {
var result = 0;
for (var i = 0; i < length; i++) {
result *= 256;
result += this.array[this.index + length - i - 1];
}
this.index += length;
}

readShort() {
return this.readIntegerValue(2);
}

readInt() {
return this.readIntegerValue(4);
}

readLong() {
return this.readIntegerValue(8);
}
}
63 changes: 52 additions & 11 deletions content.js
@@ -1,24 +1,65 @@
'use strict';

function initializeExtension() {
// Process all tip buttons.
var clientUrl = '';
var receiverId = '';
var tag = '';
var buttons = document.getElementsByClassName('nyzo-tip-button');
for (var i = 0; i < buttons.length; i++) {
var button = buttons[i];

// Get the tip configuration, if present.
var tipClientUrl = '';
var tipReceiverId = '';
var tipTag = '';
var tipButtons = document.getElementsByClassName('nyzo-tip-button');
for (var i = 0; i < tipButtons.length; i++) {
var button = tipButtons[i];

// Modify the classes to show that the extension was installed.
button.classList.add('nyzo-extension-installed');
button.classList.remove('nyzo-extension-not-installed');

// If valid, store the client URL, receiver ID, and tag.
tipClientUrl = button.dataset.clientUrl;
tipReceiverId = button.dataset.receiverId;
tipTag = cleanTag(button.dataset.tag);
}
var tipConfiguration = new MicropayConfiguration(tipClientUrl, tipReceiverId, tipTag, '', 0);

// Get Micropay configurations, if present.
var micropayConfigurations = [];
var micropayButtons = document.getElementsByClassName('nyzo-micropay-button');
for (var i = 0; i < micropayButtons.length; i++) {
var button = micropayButtons[i];

// Modify the classes to show that the extension was installed.
button.classList.add('nyzo-extension-installed');
button.classList.remove('nyzo-extension-not-installed');

// If valid, store the client URL, receiver ID, and tag.
clientUrl = button.dataset.clientUrl;
receiverId = button.dataset.receiverId;
tag = cleanTag(button.dataset.tag);
const clientUrl = button.dataset.clientUrl;
const receiverId = button.dataset.receiverId;
const tag = cleanTag(button.dataset.tag);
const displayName = cleanDisplayName(button.dataset.displayName);
const amountMicronyzos = getAmountMicronyzos(button.dataset.amount);
const configuration = new MicropayConfiguration(clientUrl, receiverId, tag, displayName, amountMicronyzos);
if (isValidConfigurationForMicropay(configuration)) {
micropayConfigurations.push(configuration);
}
}

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
sendResponse({clientUrl: clientUrl, receiverId: receiverId, tag: tag});
if (request.action === 'getNyzoParameters') {
sendResponse({tipConfiguration: tipConfiguration, micropayConfigurations: micropayConfigurations});
} else if (request.action === 'micropayTransactionAvailable') {
const uniqueReferenceKey = request.uniqueReferenceKey;

chrome.storage.local.get([uniqueReferenceKey, 'privateKey'], function(extensionConfiguration) {
const privateKey = decode(extensionConfiguration.privateKey).getSeed();

const transaction = extensionConfiguration[uniqueReferenceKey];
const supplementalTransaction = createSupplementalTransaction(decode(transaction), privateKey);
const detailObject = {transaction: transaction,
supplementalTransaction: nyzoStringFromTransaction(supplementalTransaction.getBytes(true))};
const event = new CustomEvent('micropayTransactionAvailable', { detail: detailObject });
document.dispatchEvent(event);
});
}
});
}

Expand Down
66 changes: 52 additions & 14 deletions extensionUtil.js
@@ -1,3 +1,5 @@
const genesisBlockHash = hexStringAsUint8Array('bc4cca2a2a50a229-256ae3f5b2b5cd49-aa1df1e2d0192726-c4bb41cdcea15364');

function isValidPrivateKey(keyString) {
var valid = false;
if (typeof keyString === 'string') {
Expand All @@ -20,13 +22,18 @@ function isValidPublicIdentifier(identifierString) {
return valid;
}

function getTipAmountMicronyzos(tipString) {
return Math.floor(+tipString * 1000000);
function getAmountMicronyzos(valueString) {
return Math.floor(+valueString * 1000000);
}

function isValidTipAmount(tipString) {
var tipAmountMicronyzos = getTipAmountMicronyzos(tipString);
return tipAmountMicronyzos >= 2 && tipAmountMicronyzos <= 100 * 1000000;
var tipAmountMicronyzos = getAmountMicronyzos(tipString);
return tipAmountMicronyzos >= 2 && tipAmountMicronyzos <= 10 * 1000000;
}

function isValidMaximumMicropayAmount(micropayString) {
var maximumAmountMicronyzos = getAmountMicronyzos(micropayString);
return maximumAmountMicronyzos >= 2 && maximumAmountMicronyzos <= 50 * 1000000;
}

function isValidClientUrl(clientUrl) {
Expand Down Expand Up @@ -57,31 +64,44 @@ function cleanTag(tag) {
if (typeof tag !== 'string') {
tag = '';
}
return tag.replace(/[^\w_]/g, '');
return tag.replace(/[^\w_]/g, '').substring(0, 32);
}

function submitTransaction(timestamp, senderPrivateSeed, previousHashHeight, previousBlockHash, receiverIdentifier,
micronyzosToSend, senderData, endpoint, callback) {
function cleanDisplayName(name) {
if (typeof name !== 'string') {
name = '';
}
return name.replace(/[^\w_ ]/g, '');
}

function submitTransaction(timestamp, senderPrivateSeed, receiverIdentifier, micronyzosToSend, senderData, endpoint,
callback) {

// Create and sign the transaction.
var transaction = new Transaction();
transaction.setTimestamp(timestamp);
transaction.setAmount(micronyzosToSend);
transaction.setRecipientIdentifier(receiverIdentifier);
transaction.setPreviousHashHeight(previousHashHeight);
transaction.setPreviousBlockHash(previousBlockHash);
transaction.setPreviousHashHeight(0);
transaction.setPreviousBlockHash(genesisBlockHash);
transaction.setSenderData(senderData);
transaction.sign(senderPrivateSeed);

var httpRequest = new XMLHttpRequest();
var transactionString = nyzoStringFromTransaction(transaction.getBytes(true));
httpRequest.onreadystatechange = function() {
if (this.readyState == 4) { // 4 == "DONE"
var result = JSON.parse(this.responseText);
var result = null;
try {
result = JSON.parse(this.responseText);
} catch (exception) {
errors = ['The response from the server was not valid.'];
}
var success = false;
var messages = null;
var warnings = null;
var errors = null;
if (typeof result === 'object') {
if (typeof result === 'object' && result != null) {
// Store the warnings and errors.
if (typeof result.errors === 'object') {
errors = result.errors;
Expand All @@ -103,7 +123,7 @@ function submitTransaction(timestamp, senderPrivateSeed, previousHashHeight, pre

// Ensure some feedback is provided.
if (messages === null && warnings === null && errors === null) {
errors = ['The tip failed to send.'];
errors = ['The transaction failed to send.'];
}
if (messages === null) {
messages = [];
Expand All @@ -112,12 +132,30 @@ function submitTransaction(timestamp, senderPrivateSeed, previousHashHeight, pre
warnings = [];
}

callback(success, messages, warnings, errors);
callback(success, messages, warnings, errors, transactionString);
}
};

var transactionString = nyzoStringFromTransaction(transaction.getBytes(true));
var fullUrl = endpoint + '?transaction=' + transactionString;
httpRequest.open('GET', fullUrl, true);
httpRequest.send();
}

function createSupplementalTransaction(referenceTransaction, senderPrivateSeed) {
// Create and sign the transaction with a current timestamp, an amount of 0, and all other fields the same as the
// reference transaction.
const supplementalTransaction = new Transaction();
supplementalTransaction.setTimestamp(Date.now());
supplementalTransaction.setAmount(1);
supplementalTransaction.setRecipientIdentifier(referenceTransaction.recipientIdentifier);
supplementalTransaction.setPreviousHashHeight(0);
supplementalTransaction.setPreviousBlockHash(genesisBlockHash);
supplementalTransaction.setSenderData(referenceTransaction.senderData);
supplementalTransaction.sign(senderPrivateSeed);

return supplementalTransaction;
}

function isUndefined(value) {
return value === void(0);
}
9 changes: 6 additions & 3 deletions manifest.json
@@ -1,7 +1,7 @@
{
"name": "Nyzo",
"version": "1",
"description": "Send tips with Nyzo",
"version": "2",
"description": "Send tips and pay for content with Nyzo",

"permissions": [
"activeTab",
Expand Down Expand Up @@ -29,7 +29,10 @@
},

"content_scripts": [{
"js": ["util.js", "extensionUtil.js", "content.js"],
"js": ["sha256.min.js", "nacl.min.js", "byteBuffer.js", "transaction.js", "util.js", "nyzoString.js",
"extensionUtil.js", "micropayConfiguration.js", "content.js"],


"matches": ["<all_urls>"]
}],

Expand Down
22 changes: 22 additions & 0 deletions micropayConfiguration.js
@@ -0,0 +1,22 @@
class MicropayConfiguration {
constructor(clientUrl, receiverId, tag, displayName, amountMicronyzos) {
this.clientUrl = clientUrl;
this.receiverId = receiverId;
this.tag = tag;
this.displayName = displayName;
this.amountMicronyzos = amountMicronyzos;
}
}

function isValidConfigurationForTips(configuration) {
return configuration != null &&
isValidClientUrl(configuration.clientUrl) &&
isValidPublicIdentifier(configuration.receiverId) &&
configuration.amountMicronyzos === 0;
}

function isValidConfigurationForMicropay(configuration) {
return isValidClientUrl(configuration.clientUrl) &&
isValidPublicIdentifier(configuration.receiverId) &&
configuration.amountMicronyzos > 0;
}
8 changes: 5 additions & 3 deletions nyzoString.js
Expand Up @@ -100,13 +100,15 @@ function decode(encodedString) {
var contentBytes = expandedArray.subarray(headerLength, expandedArray.length - checksumLength);

// Make the object from the content array.
if (prefix == 'key_') {
if (prefix === 'key_') {
result = new NyzoStringPrivateSeed(contentBytes);
} else if (prefix == 'id__') {
} else if (prefix === 'id__') {
result = new NyzoStringPublicIdentifier(contentBytes);
} else if (prefix == 'pre_') {
} else if (prefix === 'pre_') {
result = new NyzoStringPrefilledData(contentBytes.subarray(0, 32),
contentBytes.subarray(33, contentBytes.length));
} else if (prefix === 'tx__') {
result = Transaction.fromBytes(contentBytes);
}
}
}
Expand Down
11 changes: 9 additions & 2 deletions options.html
Expand Up @@ -11,7 +11,7 @@
</head>
<body>
<h1>
Nyzo tip extension options
Nyzo extension options
</h1>

<div class="container">
Expand All @@ -21,13 +21,20 @@ <h1>
<label class="label" for="baseTip">base tip amount, in Nyzos</label>
<input autocomplete="off" id="baseTip" class="input" spellcheck="false">

<label class="label" for="maximumMicropayAmount">maximum Micropay amount, in Nyzos</label>
<input autocomplete="off" id="maximumMicropayAmount" class="input" spellcheck="false">

<div class="notice">
This displays a dialog with options for 1x, 2x, and 5x the base tip amount. So, with a base tip amount of
&cap;0.1, the dialog provides options of &cap;0.1, &cap;0.2, and &cap;0.5.
</div>

<div class="notice">
The tip amount must be at least &cap;0.000002 and no more than &cap;100.000000.
The tip amount must be at least &cap;0.000002 and no more than &cap;10.000000.
</div>

<div class="notice">
The maximum Micropay amount must be at least &cap;0.000002 and no more than &cap;50.000000.
</div>
</div>
</body>
Expand Down

0 comments on commit 924c385

Please sign in to comment.