Skip to content

Commit

Permalink
Arweave.init default removes subdomain
Browse files Browse the repository at this point in the history
  • Loading branch information
rosmcmahon committed Feb 15, 2023
1 parent 568a0f1 commit c066e0e
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 123 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "arweave",
"version": "1.12.7",
"version": "1.13.0",
"description": "Arweave JS client library",
"main": "./node/index.js",
"react-native": "./node/index.js",
Expand Down
4 changes: 2 additions & 2 deletions src/common/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ export default class Api {
response.data = (await res.arrayBuffer()) as T;
} else if (responseType === "text") {
response.data = (await res.text()) as T;
} else if (responseType === "webstream"){
response.data = response.body as T;
} else if (responseType === "webstream") {
response.data = response.body as T;
} else if (contentType?.startsWith("application/json")) {
try {
await res.clone().json(); //the test
Expand Down
45 changes: 22 additions & 23 deletions src/web/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Arweave from "./common";
import { ApiConfig } from "./lib/api";
import { getDefaultConfig } from './net-config'
import { getDefaultConfig } from "./net-config";

declare global {
interface Window {
Expand All @@ -12,32 +12,31 @@ declare global {
}

Arweave.init = function (apiConfig: ApiConfig = {}): Arweave {

const defaults = {
host: "arweave.net",
port: 443,
protocol: "https",
};

if(
typeof location !== "object"
|| !location.protocol
|| !location.hostname
){
return new Arweave({
host: "arweave.net",
port: 443,
protocol: "https",
};

if (
typeof location !== "object" ||
!location.protocol ||
!location.hostname
) {
return new Arweave({
...apiConfig,
...defaults,
});
}

// window.location.protocol has a trailing colon (http:, https:, file: etc)
const locationProtocol = location.protocol.replace(":", "");
const locationHost = location.hostname;
const locationPort = location.port
? parseInt(location.port)
: locationProtocol == "https"
? 443
: 80;
}

// window.location.protocol has a trailing colon (http:, https:, file: etc)
const locationProtocol = location.protocol.replace(":", "");
const locationHost = location.hostname;
const locationPort = location.port
? parseInt(location.port)
: locationProtocol == "https"
? 443
: 80;

const defaultConfig = getDefaultConfig(locationProtocol, locationHost);

Expand Down
108 changes: 56 additions & 52 deletions src/web/net-config.ts
Original file line number Diff line number Diff line change
@@ -1,65 +1,69 @@
export interface NetConfig {
protocol: string,
host: string,
port?: number,
protocol: string;
host: string;
port?: number;
}

/** exhaustive localhost testing */
const isLocal = (protocol: string, hostname: string)=>{
const regexLocalIp = /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
const isLocal = (protocol: string, hostname: string) => {
const regexLocalIp = /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/;

const split = hostname.split('.')
const tld = split[split.length - 1] // check if subdomain on the localhost
const split = hostname.split(".");
const tld = split[split.length - 1]; // check if subdomain on the localhost

const localStrings = ["localhost", "[::1]"]
const localStrings = ["localhost", "[::1]"];

return localStrings.includes(hostname) || protocol == "file"
|| localStrings.includes(tld) || !!hostname.match(regexLocalIp) || !!tld.match(regexLocalIp)
}
return (
localStrings.includes(hostname) ||
protocol == "file" ||
localStrings.includes(tld) ||
!!hostname.match(regexLocalIp) ||
!!tld.match(regexLocalIp)
);
};

/** simplified tests for ip addresses */
const isIpAdress = (host: string)=> {
// an IPv6 location.hostname (and only IPv6 hostnames) must be surrounded by square brackets
const isIpv6 = host.charAt(0) === '['
// Potential speed-up for IPv4 detection:
// the tld of a domain name cannot be a number (IDN location.hostnames appear to be converted, needs further clarification)
const regexMatchIpv4 = /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/

return !!host.match(regexMatchIpv4) || isIpv6
}

export const getDefaultConfig = (protocol: string, host: string): NetConfig=>{
const isIpAdress = (host: string) => {
// an IPv6 location.hostname (and only IPv6 hostnames) must be surrounded by square brackets
const isIpv6 = host.charAt(0) === "[";
// Potential speed-up for IPv4 detection:
// the tld of a domain name cannot be a number (IDN location.hostnames appear to be converted, needs further clarification)
const regexMatchIpv4 =
/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/;

// If we're running in what looks like a local dev environment
// then default to using arweave.net
if(isLocal(protocol, host)){
return {
protocol: "https",
host: "arweave.net",
port: 443,
};
}
return !!host.match(regexMatchIpv4) || isIpv6;
};

//check if hostname is an IP address before removing first subdomain
if(!isIpAdress(host)){
let split = host.split('.')
if(split.length >=3){
split.shift()
const parentDomain = split.join('.')
return {
protocol,
host: parentDomain,
}
}
}
export const getDefaultConfig = (protocol: string, host: string): NetConfig => {
// If we're running in what looks like a local dev environment
// then default to using arweave.net
if (isLocal(protocol, host)) {
return {
protocol: "https",
host: "arweave.net",
port: 443,
};
}

// there are 2 potential garbage returns here:
// a non-GW ip address & a non-GW hostname without ArNS. garbage in, garbage out.
// they should be overridden with user inputs in apiConfig.
// otherwise we have a valid ip based GW address.
return {
protocol,
host,
};
}
//check if hostname is an IP address before removing first subdomain
if (!isIpAdress(host)) {
let split = host.split(".");
if (split.length >= 3) {
split.shift();
const parentDomain = split.join(".");
return {
protocol,
host: parentDomain,
};
}
}

// there are 2 potential garbage returns here:
// a non-GW ip address & a non-GW hostname without ArNS. garbage in, garbage out.
// they should be overridden with user inputs in apiConfig.
// otherwise we have a valid ip based GW address.
return {
protocol,
host,
};
};
89 changes: 46 additions & 43 deletions test/net-config.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,54 @@
import { expect } from "chai";
import {} from "mocha";
import { getDefaultConfig } from '../src/web/net-config'
import { getDefaultConfig } from "../src/web/net-config";


describe('Net Config', function () {
describe("Net Config", function () {
this.timeout(2_000);

it("should detect localhost dev environment", async function () {
const file = getDefaultConfig('file', '')
expect(file.protocol).equal('https')
expect(file.host).equal('arweave.net')
expect(file.port).equal(443)
const localhost = getDefaultConfig('http', 'sub.fake.localhost')
expect(localhost.protocol).equal('https')
expect(localhost.host).equal('arweave.net')
expect(localhost.port).equal(443)
const ipv4 = getDefaultConfig('http', '127.0.0.255')
expect(ipv4.protocol).equal('https')
expect(ipv4.host).equal('arweave.net')
expect(ipv4.port).equal(443)
const ipv6 = getDefaultConfig('http', '[::1]')
expect(ipv6.protocol).equal('https')
expect(ipv6.host).equal('arweave.net')
expect(ipv6.port).equal(443)
it("should detect localhost dev environment", async function () {
const file = getDefaultConfig("file", "");
expect(file.protocol).equal("https");
expect(file.host).equal("arweave.net");
expect(file.port).equal(443);
const localhost = getDefaultConfig("http", "sub.fake.localhost");
expect(localhost.protocol).equal("https");
expect(localhost.host).equal("arweave.net");
expect(localhost.port).equal(443);
const ipv4 = getDefaultConfig("http", "127.0.0.255");
expect(ipv4.protocol).equal("https");
expect(ipv4.host).equal("arweave.net");
expect(ipv4.port).equal(443);
const ipv6 = getDefaultConfig("http", "[::1]");
expect(ipv6.protocol).equal("https");
expect(ipv6.host).equal("arweave.net");
expect(ipv6.port).equal(443);
});

it("should remove first subdomain when appropriate", async()=> {
const subdomain = getDefaultConfig('https', 'arnsname.example.com')
expect(subdomain.protocol).equal('https')
expect(subdomain.host).equal('example.com')
expect(subdomain.port).undefined
const generated = getDefaultConfig('https', 'ngnrj2ntoigcuduz2xwowwzaxojwinwb7qugblukljxkhrymozaq.example.com')
expect(generated.protocol).equal('https')
expect(generated.host).equal('example.com')
expect(generated.port).undefined
})

it("should let ip addresses pass through", async()=> {
const ipv4 = getDefaultConfig('https', '123.123.123.123')
expect(ipv4.protocol).equal('https')
expect(ipv4.host).equal('123.123.123.123')
expect(ipv4.port).undefined
const ipv6 = getDefaultConfig('https', '[2001:db8:3333:4444:5555:6666:7777:8888]')
expect(ipv6.protocol).equal('https')
expect(ipv6.host).equal('[2001:db8:3333:4444:5555:6666:7777:8888]')
expect(ipv6.port).undefined
})

it("should remove first subdomain when appropriate", async () => {
const subdomain = getDefaultConfig("https", "arnsname.example.com");
expect(subdomain.protocol).equal("https");
expect(subdomain.host).equal("example.com");
expect(subdomain.port).undefined;
const generated = getDefaultConfig(
"https",
"ngnrj2ntoigcuduz2xwowwzaxojwinwb7qugblukljxkhrymozaq.example.com"
);
expect(generated.protocol).equal("https");
expect(generated.host).equal("example.com");
expect(generated.port).undefined;
});

})
it("should let ip addresses pass through", async () => {
const ipv4 = getDefaultConfig("https", "123.123.123.123");
expect(ipv4.protocol).equal("https");
expect(ipv4.host).equal("123.123.123.123");
expect(ipv4.port).undefined;
const ipv6 = getDefaultConfig(
"https",
"[2001:db8:3333:4444:5555:6666:7777:8888]"
);
expect(ipv6.protocol).equal("https");
expect(ipv6.host).equal("[2001:db8:3333:4444:5555:6666:7777:8888]");
expect(ipv6.port).undefined;
});
});

0 comments on commit c066e0e

Please sign in to comment.