diff --git a/app/browser/webtorrent.js b/app/browser/webtorrent.js index f5a44945c9d..7f08ba2e2be 100644 --- a/app/browser/webtorrent.js +++ b/app/browser/webtorrent.js @@ -1,11 +1,19 @@ const electron = require('electron') const ipc = electron.ipcMain +const appUrlUtil = require('../../js/lib/appUrlUtil') const messages = require('../../js/constants/messages') +const Filtering = require('../filtering') // Set to see communication between WebTorrent and torrent viewer tabs const DEBUG_IPC = false if (DEBUG_IPC) console.log('WebTorrent IPC debugging enabled') +var VIEWER_URL = appUrlUtil.getTorrentExtUrl('webtorrent.html') + +function getViewerURL (torrentUrl) { + return VIEWER_URL + '#' + encodeURIComponent(torrentUrl) +} + // Connects to the BitTorrent network // Communicates with the WebTorrentRemoteClients via message passing let server = null @@ -23,7 +31,7 @@ function init (state, action) { channels[msg.clientKey] = e.sender server.receive(msg) }) - + setupFiltering() return state } @@ -43,6 +51,64 @@ function send (msg) { channel.send(messages.TORRENT_MESSAGE, msg) } +function setupFiltering () { + Filtering.registerHeadersReceivedFilteringCB(function (details, isPrivate) { + if (details.method !== 'GET') { + return {} + } + if (!isTorrentFile(details)) { + return {} + } + + var viewerUrl = getViewerURL(details.url) + + return { + responseHeaders: { + 'Location': [ viewerUrl ] + }, + statusLine: 'HTTP/1.1 301 Moved Permanently', + resourceName: 'webtorrent' + } + }) +} + +/** + * Check if the request is a torrent file. + * @param {Object} details First argument of the webRequest.onHeadersReceived + * event. The properties "responseHeaders" and "url" + * are read. + * @return {boolean} True if the resource is a torrent file. + */ +function isTorrentFile (details) { + var header = getHeader(details.responseHeaders, 'content-type') + if (header) { + var headerValue = header.toLowerCase().split(';', 1)[0].trim() + if (headerValue === 'application/x-bittorrent') { + return true + } + if (headerValue === 'application/octet-stream') { + if (details.url.toLowerCase().indexOf('.torrent') > 0) { + return true + } + var cdHeader = + getHeader(details.responseHeaders, 'content-disposition') + if (cdHeader && /\.torrent(["']|$)/i.test(cdHeader)) { + return true + } + } + } + return false +} + +function getHeader (headers, headerName) { + var headerNames = Object.keys(headers) + for (var i = 0; i < headerNames.length; ++i) { + if (headerNames[i].toLowerCase() === headerName) { + return headers[headerNames[i]][0] + } + } +} + module.exports = { init, resourceName: 'webtorrent' diff --git a/app/extensions/torrent/locales/en-US/app.properties b/app/extensions/torrent/locales/en-US/app.properties index 1cfc2137536..c714874277a 100644 --- a/app/extensions/torrent/locales/en-US/app.properties +++ b/app/extensions/torrent/locales/en-US/app.properties @@ -1,7 +1,7 @@ startPrompt=Start Downloading "{{name}}"? startPromptUntitled=Start Downloading? startDownload=Start Download -saveTorrentFile=Save Torrent File +saveTorrentFile=Save Torrent File... legalNotice=When you start a torrent, its data will be made available to others by means of upload. You are responsible for abiding by your local laws. missingFilesList=Click "Start Download" to load the torrent file list. loadingFilesList=Loading the torrent file list... @@ -18,3 +18,5 @@ downloadFile=Save File torrentStatus=Torrent Status torrentLoadingInfo=Loading torrent info... torrentLoadingMedia=Loading... +copyMagnetLink=Copy Magnet Link +webtorrentPage=WebTorrent diff --git a/app/extensions/torrent/webtorrent.html b/app/extensions/torrent/webtorrent.html index b22cfbe6a17..6826dd3825a 100644 --- a/app/extensions/torrent/webtorrent.html +++ b/app/extensions/torrent/webtorrent.html @@ -10,10 +10,10 @@ -
+ diff --git a/app/filtering.js b/app/filtering.js index c604c1667f4..1a05dc115d7 100644 --- a/app/filtering.js +++ b/app/filtering.js @@ -287,7 +287,6 @@ function registerForBeforeSendHeaders (session, partition) { */ function registerForHeadersReceived (session, partition) { const isPrivate = module.exports.isPrivate(partition) - // Note that onBeforeRedirect listener doesn't take a callback session.webRequest.onHeadersReceived(function (details, cb) { // Using an electron binary which isn't from Brave if (shouldIgnoreUrl(details)) { @@ -306,7 +305,10 @@ function registerForHeadersReceived (session, partition) { continue } if (results.responseHeaders) { - cb({responseHeaders: results.responseHeaders}) + cb({ + responseHeaders: results.responseHeaders, + statusLine: results.statusLine + }) return } } diff --git a/js/webtorrent/components/app.js b/js/webtorrent/components/app.js new file mode 100644 index 00000000000..3af58d12261 --- /dev/null +++ b/js/webtorrent/components/app.js @@ -0,0 +1,35 @@ +const React = require('react') + +const MediaViewer = require('./mediaViewer') +const TorrentViewer = require('./torrentViewer') + +class App extends React.Component { + render () { + const { + ix, + name, + torrentId, + torrentIdProtocol, + torrent, + serverUrl, + errorMessage + } = this.props.store + + if (torrent && ix != null) { + return + } else { + return ( + + ) + } + } +} + +module.exports = App diff --git a/js/webtorrent/components/mediaViewer.js b/js/webtorrent/components/mediaViewer.js index 95588155e3d..09ebd41260b 100644 --- a/js/webtorrent/components/mediaViewer.js +++ b/js/webtorrent/components/mediaViewer.js @@ -19,16 +19,17 @@ const SUPPORTED_AUDIO_EXTENSIONS = [ module.exports = class MediaViewer extends React.Component { render () { - const torrent = this.props.torrent - const ix = this.props.ix + const { torrent, serverUrl, ix } = this.props + const file = torrent.files[ix] + const fileURL = serverUrl && (serverUrl + '/' + ix) + const fileExt = file && getExtension(file.name) const isVideo = SUPPORTED_VIDEO_EXTENSIONS.includes(fileExt) const isAudio = SUPPORTED_AUDIO_EXTENSIONS.includes(fileExt) - const fileURL = torrent.serverURL && (torrent.serverURL + '/' + ix) let content - if (torrent.serverURL == null) { + if (!file || !serverUrl) { content =
} else if (isVideo) { content =