diff --git a/README.md b/README.md index 6304694..c79c318 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,7 @@ It aims to implement native-like dat support possible in Firefox. This means: ## Usage -1. Grab [this fork of dat-gateway](https://github.com/sammacbeth/dat-gateway) and run it: - - ```bash - git clone https://github.com/sammacbeth/dat-gateway.git - cd dat-gateway - npm install - ./bin.js - ``` +1. Install [dat-fox-helper](https://github.com/sammacbeth/dat-fox-helper) 2. Install the extension from the [Mozilla Addon Store](https://addons.mozilla.org/en-US/firefox/addon/dat-p2p-protocol/) @@ -50,16 +43,11 @@ You can now load the `addon` folder as a temporary addon in Firefox: * `http://{hash}` * `dat://{hostname}` (using [Dat Discovery](https://github.com/beakerbrowser/beaker/wiki/Authenticated-Dat-URLs-and-HTTPS-to-Dat-Discovery)) * Toggle between `https` to `dat` protocol for Dat-enabled sites. - -## What does not work - -Due to limitations in the WebExtensions protocol handler API, non main-frame `dat://` urls do not load. For static resources we can circumvent this by rewriting `dat://` to `http://` in HTML files using a [StreamFilter](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest/StreamFilter). However, dynamically generated requests will fail. - -Any Dat site which relies on the [DatArchive](https://beakerbrowser.com/docs/apis/dat.html) will not work. +* Create and fork archives. +* `DatArchive` [API](https://beakerbrowser.com/docs/apis/dat.html) ## How it works 1. The [protocol handler](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/manifest.json/protocol_handlers) redirects `dat://` urls to a special handler domain (`dat.redirect`), passing the full url. 2. A [webRequest](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/webRequest) listener intercepts requests to this domain and redirects to a `http://` URL with the dat key or hostname as the origin. 3. A [proxy PAC](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/proxy) file intercepts hostnames matching a dat key pattern, or hostnames the user has explicitly ask to load over dat. Requests for these URLs are proxied via the dat-gateway (acting as a HTTP proxy). This allows us to make 'fake' hostnames work, and create the origins we need for dat sites. - diff --git a/addon/manifest.json b/addon/manifest.json index 2b0c807..0d0b5f3 100644 --- a/addon/manifest.json +++ b/addon/manifest.json @@ -36,7 +36,7 @@ "default_icon": "assets/dat-hexagon.svg" }, "options_ui": { - "page": "options_page/options.html", - "browser_style": true + "page": "pages/options.html", + "browser_style": false } } \ No newline at end of file diff --git a/addon/options_page/options.html b/addon/options_page/options.html deleted file mode 100644 index 1fc665d..0000000 --- a/addon/options_page/options.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - -
- - - -
- - - \ No newline at end of file diff --git a/addon/dialog.html b/addon/pages/dialog.html similarity index 95% rename from addon/dialog.html rename to addon/pages/dialog.html index b8a88f5..ee4c2fb 100644 --- a/addon/dialog.html +++ b/addon/pages/dialog.html @@ -4,7 +4,7 @@ Create Dat - +
@@ -48,5 +48,5 @@

Select an archive from your library

- + \ No newline at end of file diff --git a/addon/pages/options.html b/addon/pages/options.html new file mode 100644 index 0000000..2cd6923 --- /dev/null +++ b/addon/pages/options.html @@ -0,0 +1,38 @@ + + + + + + + + + +
+
+
+

Actions:

+ +
+
+
+
+

Settings:

+
+
+ + +
+ +
+
+
+
+ + + \ No newline at end of file diff --git a/addon/options_page/options.js b/addon/pages/options.js similarity index 100% rename from addon/options_page/options.js rename to addon/pages/options.js diff --git a/addon/popup/popup.html b/addon/pages/popup.html similarity index 100% rename from addon/popup/popup.html rename to addon/pages/popup.html diff --git a/addon/pages/setup.html b/addon/pages/setup.html new file mode 100644 index 0000000..7f7a03a --- /dev/null +++ b/addon/pages/setup.html @@ -0,0 +1,65 @@ + + + + + + + Dat-fox Setup + + +
+
+
+

Dat-fox: Dat + Firefox

+

+ You're almost ready to browse Dat, but first we need to make sure + everything is setup. +

+

If you didn't already, you need to install the dat-fox helper:

+
    +
  • Mac/Linux: curl -o- https://raw.githubusercontent.com/sammacbeth/dat-fox-helper/master/installer.sh | bash
  • +
  • Windows: Manual install instructions.
  • +
+

+ Once dat-fox-helper is installed, click below to test that your browser + can communicate with the helper process. +

+ +
+
+
+
+
+
+
+ +
+
+ + + \ No newline at end of file diff --git a/addon/pages/setup.js b/addon/pages/setup.js new file mode 100644 index 0000000..04a18e1 --- /dev/null +++ b/addon/pages/setup.js @@ -0,0 +1,70 @@ + +const { bridge, resetBridge } = browser.extension.getBackgroundPage(); + +const button = document.getElementById('test'); +const testResults = document.getElementById('test-results'); + +function createCheckAlert() { + const elem = document.createElement('div'); + elem.setAttribute('class', 'alert alert-primary'); + elem.setAttribute('role', 'alert'); + return elem; +} + +async function testGateway(setLabel) { + setLabel('Attempting to start gateway...'); + const port = await resetBridge(); + setLabel(`Successfully started dat gateway at localhost:${port}.`); + return true; +} + +async function testVersion(setLabel) { + setLabel('Checking helper version...'); + const version = await bridge.postMessage({ action: 'getVersion' }); + const wantedVersion = '0.0.5'; + if (version < wantedVersion) { + setLabel(`Helper version ${version} not up-to-date. Latest is ${wantedVersion}`); + return false; + } + setLabel(`Helper version ${version} up-to-date`); + return true; +} + +button.onclick = async () => { + button.innerText = 'Testing...'; + button.setAttribute('disabled', true); + testResults.innerHTML = ''; + const bridgeCheck = createCheckAlert(); + bridgeCheck.innerHTML = '

Checking helper connection

'; + testResults.appendChild(bridgeCheck); + const resultList = document.getElementById('results'); + + const tests = [testGateway, testVersion]; + let failure = false; + for (let i = 0; i < tests.length; i++) { + const test = tests[i]; + const testElem = document.createElement('li'); + resultList.appendChild(testElem); + try { + const res = await test((label) => testElem.innerText = label); + if (!res) { + failure = true; + break; + } + } catch(e) { + testElem.innerText = `${testElem.innerText} ${e}`; + failure = true; + break; + } + } + + if (failure) { + bridgeCheck.setAttribute('class', 'alert alert-danger'); + } else { + bridgeCheck.setAttribute('class', 'alert alert-success'); + document.getElementById('ready-to-go').setAttribute('class', 'col visible'); + } + + button.removeAttribute('disabled'); + button.innerText = 'Test'; +}; \ No newline at end of file diff --git a/background/background.js b/background/background.js index e489f29..abed693 100644 --- a/background/background.js +++ b/background/background.js @@ -18,16 +18,19 @@ proxyReady.then(() => { const bridge = new NativeBridge(); global.bridge = bridge; -bridge.connect().then(() => { +global.resetBridge = async () => { + if (bridge.connected) { + bridge.disconnect(); + } + await bridge.connect(); console.log('bridge is ready'); useNativeBridge(bridge); const port = 3000 + Math.floor(Math.random() * 500); - bridge.postMessage({ + await bridge.postMessage({ action: 'startGateway', port: port, - }).then(() => { - setGatewayAddress(`http://localhost:${port}`); - }, (e) => console.error('error starting gateway', e)); + }); + setGatewayAddress(`http://localhost:${port}`); // add actions which the helper API supports ['resolveName', 'getInfo', 'stat', 'readdir', 'history', 'readFile', 'writeFile', 'mkdir', 'unlink', 'rmdir', 'diff', 'commit', 'revert', 'download', 'createFileActivityStream', @@ -47,10 +50,16 @@ bridge.connect().then(() => { await closeArchives.map(({ url }) => bridge.postMessage({ action: 'closeArchive', url })); } }, 60000); -}, (e) => { + return port; +}; + +global.resetBridge().catch((e) => { console.log('bridge loading failed, using local Dat API implementation', e); + console.log('opening setup page'); + browser.tabs.create({ url: browser.extension.getURL('setup.html')}); }); + // actions in this set are forwarded to the native bridge const passthroughActions = new Set(); diff --git a/background/dialog.js b/background/dialog.js index 34c581c..7095a8c 100644 --- a/background/dialog.js +++ b/background/dialog.js @@ -6,7 +6,7 @@ export default { const win = await browser.windows.create({ allowScriptsToClose: true, type: 'popup', - url: `/dialog.html#${JSON.stringify(message)}`, + url: `/pages/dialog.html#${JSON.stringify(message)}`, width: 500, height: 400, }); diff --git a/background/native-bridge.js b/background/native-bridge.js index 5893fc1..c80bab4 100644 --- a/background/native-bridge.js +++ b/background/native-bridge.js @@ -4,6 +4,7 @@ export default class { constructor() { this.messageIdx = 0; this.waitingForResponse = new Map(); + this.connected = false; } connect() { @@ -18,6 +19,7 @@ export default class { }; const timer = setTimeout(() => { this.port.onDisconnect.removeListener(disconnectListener); + this.connected = true; resolve(); }, 2000); this.port.onDisconnect.addListener(disconnectListener); @@ -46,4 +48,9 @@ export default class { this.port.postMessage(message); }); } + + disconnect() { + this.connected = false; + this.port.disconnect(); + } } diff --git a/background/page-action.js b/background/page-action.js index d33cf4a..411d132 100644 --- a/background/page-action.js +++ b/background/page-action.js @@ -27,7 +27,7 @@ export function showDatSecureIcon(tabId) { tabId, title: 'Secure Dat Site', }); - browser.pageAction.setPopup({ tabId, popup: 'popup/popup.html' }); + browser.pageAction.setPopup({ tabId, popup: 'pages/popup.html' }); browser.pageAction.show(tabId); } diff --git a/dialog/dialog.js b/dialog/dialog.js index e651a3d..865f058 100644 --- a/dialog/dialog.js +++ b/dialog/dialog.js @@ -55,8 +55,8 @@ async function setupForm() { desc.setAttribute('value', opts.description || ''); onSubmit(() => DatArchive.create({ - title: title.getAttribute('value'), - desc: desc.getAttribute('value'), + title: title.value, + desc: desc.value, }).then((archive) => { port.postMessage({ action: 'dialogResponse',