mirror of
https://github.com/transatoshi-mw/grin-web-wallet.git
synced 2025-10-06 15:52:47 +00:00
343 lines
7.7 KiB
JavaScript
Executable File
343 lines
7.7 KiB
JavaScript
Executable File
// Use strict
|
|
"use strict";
|
|
|
|
|
|
// Classes
|
|
|
|
// Tor class
|
|
class Tor {
|
|
|
|
// Public
|
|
|
|
// Initialize
|
|
static initialize() {
|
|
|
|
// Set browser support Tor to true if is an Onion Service or unknown otherwise
|
|
Tor.browserSupportsTor = (Tor.isOnionService() === true) ? true : Tor.SUPPORT_UNKNOWN;
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Return checking if browser supports Tor
|
|
return Tor.checkIfBrowserSupportsTor().then(function() {
|
|
|
|
// Check if browser's Tor support is unknown
|
|
if(Tor.browserSupportsTor === Tor.SUPPORT_UNKNOWN) {
|
|
|
|
// Window online event
|
|
$(window).on("online", function() {
|
|
|
|
// Check if browser supports Tor
|
|
Tor.checkIfBrowserSupportsTor();
|
|
});
|
|
}
|
|
|
|
// Resolve
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
|
|
// Is supported
|
|
static isSupported() {
|
|
|
|
// Return if browser supports Tor
|
|
return Tor.browserSupportsTor === true;
|
|
}
|
|
|
|
// Is Tor URL
|
|
static isTorUrl(url) {
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Parse URL
|
|
var parsedUrl = new URL(url);
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Return false
|
|
return false;
|
|
}
|
|
|
|
// Return if address is a Tor URL
|
|
return Tor.URL_PATTERN.test(parsedUrl["protocol"] + "//" + parsedUrl["hostname"]) === true;
|
|
}
|
|
|
|
// Get Tor address from URL
|
|
static getTorAddressFromUrl(url) {
|
|
|
|
// Trim url
|
|
url = url.trim();
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Parse URL with a protocol and top-level domain added if needed
|
|
var parsedUrl = new URL(((Common.urlContainsProtocol(url) === false) ? Common.HTTP_PROTOCOL + "//" : "") + url + ((Common.urlContainsProtocol(url) === false && Common.urlContainsTopLevelDomain(url) === false) ? Tor.URL_TOP_LEVEL_DOMAIN : ""));
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Throw error
|
|
throw "Invalid URL.";
|
|
}
|
|
|
|
// Check if parsed URL is a Tor URL
|
|
if(Tor.URL_PATTERN.test(parsedUrl["protocol"] + "//" + parsedUrl["hostname"]) === false) {
|
|
|
|
// Throw error
|
|
throw "Invalid URL.";
|
|
}
|
|
|
|
// Set Tor address to the URL without its subdomain and top-level domain
|
|
var torAddress = Common.removeTopLevelDomain(Common.removeSubdomain(parsedUrl["hostname"]));
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Get public key from the Tor address
|
|
Tor.torAddressToPublicKey(torAddress);
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Throw error
|
|
throw "Invalid URL.";
|
|
}
|
|
|
|
// Return Tor address
|
|
return torAddress;
|
|
}
|
|
|
|
// Is Onion Service
|
|
static isOnionService() {
|
|
|
|
// Check if is extension or loading from file
|
|
if(Common.isExtension() === true || location["protocol"] === Common.FILE_PROTOCOL) {
|
|
|
|
// Return false
|
|
return false;
|
|
}
|
|
|
|
// Return if site is an Onion Service
|
|
return Tor.isTorUrl(location["protocol"] + "//" + location["hostname"]) === true;
|
|
}
|
|
|
|
// Public key to Tor address
|
|
static publicKeyToTorAddress(publicKey) {
|
|
|
|
// Check it public key isn't the correct length
|
|
if(publicKey["length"] !== Crypto.ED25519_PUBLIC_KEY_LENGTH) {
|
|
|
|
// Throw error
|
|
throw "Invalid public key.";
|
|
}
|
|
|
|
// Get checksum of seed, address public key, and version
|
|
var checksum = new Uint8Array(sha3_256.arrayBuffer(Common.mergeArrays([
|
|
|
|
// Seed
|
|
(new TextEncoder()).encode(Tor.ADDRESS_CHECKSUM_SEED),
|
|
|
|
// Public key
|
|
publicKey,
|
|
|
|
// Version
|
|
new Uint8Array([Tor.ADDRESS_VERSION])
|
|
])));
|
|
|
|
// Get Tor address from address public key, checksum, and version
|
|
var torAddress = base32.encode(Common.mergeArrays([
|
|
|
|
// Public key
|
|
publicKey,
|
|
|
|
// Checksum
|
|
checksum.subarray(0, Tor.ADDRESS_CHECKSUM_LENGTH),
|
|
|
|
// Version
|
|
new Uint8Array([Tor.ADDRESS_VERSION])
|
|
|
|
])).toLowerCase();
|
|
|
|
// Return Tor address
|
|
return torAddress;
|
|
}
|
|
|
|
// Tor address to public key
|
|
static torAddressToPublicKey(torAddress) {
|
|
|
|
// Check it Tor address isn't the correct length
|
|
if(torAddress["length"] !== Tor.ADDRESS_LENGTH) {
|
|
|
|
// Throw error
|
|
throw "Invalid Tor address.";
|
|
}
|
|
|
|
// Check it Tor address isn't lower case
|
|
if(Common.isLowercaseString(torAddress) === false) {
|
|
|
|
// Throw error
|
|
throw "Invalid Tor address.";
|
|
}
|
|
|
|
// Try
|
|
try {
|
|
|
|
// Decode Tor address
|
|
var decodedAddress = new Uint8Array(base32.decode.asBytes(torAddress.toUpperCase()));
|
|
}
|
|
|
|
// Catch errors
|
|
catch(error) {
|
|
|
|
// Throw error
|
|
throw "Invalid Tor address.";
|
|
}
|
|
|
|
// Check if decoded address's length is invalid
|
|
if(decodedAddress["length"] !== Crypto.ED25519_PUBLIC_KEY_LENGTH + Tor.ADDRESS_CHECKSUM_LENGTH + [Tor.ADDRESS_VERSION]["length"]) {
|
|
|
|
// Throw error
|
|
throw "Invalid Tor address.";
|
|
}
|
|
|
|
// Get checksum of seed, decoded address, and version
|
|
var checksum = new Uint8Array(sha3_256.arrayBuffer(Common.mergeArrays([
|
|
|
|
// Seed
|
|
(new TextEncoder()).encode(Tor.ADDRESS_CHECKSUM_SEED),
|
|
|
|
// Decoded address
|
|
decodedAddress.subarray(0, Crypto.ED25519_PUBLIC_KEY_LENGTH),
|
|
|
|
// Version
|
|
new Uint8Array([Tor.ADDRESS_VERSION])
|
|
])));
|
|
|
|
// Check if decoded address's checksum doesn't match the expected value
|
|
if(Common.arraysAreEqual(checksum.subarray(0, Tor.ADDRESS_CHECKSUM_LENGTH), decodedAddress.subarray(Crypto.ED25519_PUBLIC_KEY_LENGTH, Crypto.ED25519_PUBLIC_KEY_LENGTH + Tor.ADDRESS_CHECKSUM_LENGTH)) === false) {
|
|
|
|
// Throw error
|
|
throw "Invalid Tor address.";
|
|
}
|
|
|
|
// Check if decoded address's version doesn't match the expected value
|
|
if(decodedAddress[Crypto.ED25519_PUBLIC_KEY_LENGTH + Tor.ADDRESS_CHECKSUM_LENGTH] !== Tor.ADDRESS_VERSION) {
|
|
|
|
// Throw error
|
|
throw "Invalid Tor address.";
|
|
}
|
|
|
|
// Return decoded address without the checksum and version
|
|
return decodedAddress.subarray(0, Crypto.ED25519_PUBLIC_KEY_LENGTH);
|
|
}
|
|
|
|
// Address length
|
|
static get ADDRESS_LENGTH() {
|
|
|
|
// Return address length
|
|
return 56;
|
|
}
|
|
|
|
// URL top-level domain
|
|
static get URL_TOP_LEVEL_DOMAIN() {
|
|
|
|
// Return URL top-level domain
|
|
return ".onion";
|
|
}
|
|
|
|
// Private
|
|
|
|
// Check if browser supports Tor
|
|
static checkIfBrowserSupportsTor() {
|
|
|
|
// Return promise
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
// Check if online and browser's Tor support is unknown
|
|
if(navigator["onLine"] === true && Tor.browserSupportsTor === Tor.SUPPORT_UNKNOWN) {
|
|
|
|
// Return getting testing connection to Tor site
|
|
return $.get(TOR_SERVER_ADDRESS + Tor.CONNECTION_TEST_URL).then(function() {
|
|
|
|
// Set browser supports Tor
|
|
Tor.browserSupportsTor = true;
|
|
|
|
// Resolve
|
|
resolve();
|
|
|
|
// Catch errors
|
|
}).catch(function(error) {
|
|
|
|
// Clear browser supports Tor
|
|
Tor.browserSupportsTor = false;
|
|
|
|
// Resolve
|
|
resolve();
|
|
});
|
|
}
|
|
|
|
// Otherwise
|
|
else {
|
|
|
|
// Resolve
|
|
resolve();
|
|
}
|
|
});
|
|
}
|
|
|
|
// Support unknown
|
|
static get SUPPORT_UNKNOWN() {
|
|
|
|
// Return support unknown
|
|
return null;
|
|
}
|
|
|
|
// Connection test URL
|
|
static get CONNECTION_TEST_URL() {
|
|
|
|
// Return connection test URL
|
|
return getResource("./connection_test.html").substring("."["length"]);
|
|
}
|
|
|
|
// URL pattern
|
|
static get URL_PATTERN() {
|
|
|
|
// Return URL pattern
|
|
return /^[^:]+:\/\/.+\.onion$/ui;
|
|
}
|
|
|
|
// Address checksum seed
|
|
static get ADDRESS_CHECKSUM_SEED() {
|
|
|
|
// Return address checksum seed
|
|
return ".onion checksum";
|
|
}
|
|
|
|
// Address version
|
|
static get ADDRESS_VERSION() {
|
|
|
|
// Return address version
|
|
return 3;
|
|
}
|
|
|
|
// Address checksum length
|
|
static get ADDRESS_CHECKSUM_LENGTH() {
|
|
|
|
// Return address checksum length
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
|
|
// Main function
|
|
|
|
// Set global object's Tor
|
|
globalThis["Tor"] = Tor;
|