Skip to content
This repository was archived by the owner on Dec 11, 2019. It is now read-only.

Commit 21c1766

Browse files
riastradh-bravediracdeltas
authored andcommitted
Tor MVP
Support isolated_storage and tor_proxy requires brave/muon#473 Use Session::IsOffTheRecord to detect private tab requires brave/muon@edad1b2 Set Tor new identify fix #12997 requires brave/muon@7e052dd Session::IsOffTheRecord for app/filtering Refresh page after getting new identity requires brave/muon@c3d6769 implement switch Tor Private Tabs in about:newtab set isTor depending on tor private tab setting and tor availability close/re-open private tab when tor switch is toggled Recreate tor private tab at the same index it was previously at always enable new identity button for now Disable search suggestions in private mode for Tor Fix #13064 set ddg as default search engine in tor private tabs fix #13212 Disable webtorrent in tor private mode fix #13063 load favicons in Tor tabs as data: URLs fix #13065 Omit unlocked icon for HTTP onion sites Fix #12990 also fix unittests Test Plan: 1. go to http://3expgpdnrrzezf7r.onion/ in a private tab 2. no icon should be in the urlbar 3. go to https://3g2upl4pq6kufc4m.onion/ 4. you should see a lock icon disable webrtc in tor mode fix #13397 add note to shields panel about breakage in tor mode Tor binary path will be passed from browser-laptop (#13455) Disable widevine notification on Tor tabs needed for #13396 Test Plan: 1. go to https://shaka-player-demo.appspot.com in a tor private tab 2. you should not see a widevine notification disable plugins in Tor private tabs Workaround browser-context-created not being emitted for tor tabs Disable flash click to play on tor tabs TODO: figure out a way to disable widevine on a per-tab basis Test Plan: 1. ensure flash is installed and enabled in preferences 2. go to https://get.adobe.com/flashplayer/about/ 3. make sure there is no popup asking you to run flash 4. right click on the flash click-to-play element (looks like a puzzle piece) on the page. no context menu should appear. deny geolocation in tor mode fix #13447 implement new tor tabs mockup fix #12922 implement new Tor New Identity UX fix #13658 Test Plan: 1. open new private tab 2. go to check.torproject.org and open shields 3. click 'new circuit' button in shields 4. it should reload the page and show a new IP 5. open shields again, click the info circle next to 'new circuit' 5. it should open a FAQ page Bundling tor with Brave Set the tor socks port and data directory. (#13641) Pass the port and data directory down for tor to use depending on channel bind tor new circuit to hard refresh in tor tabs fix #13925 upgrade to muon 6.1.0 for tor API support
1 parent 3b5bfea commit 21c1766

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+4601
-3748
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,6 @@ app/extensions/brave/content/scripts/sync.js
8080

8181
# script used for signing for widevine
8282
signature_generator.py
83+
84+
# binaries
85+
app/extensions/bin

.npmrc

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
runtime = electron
22
target_arch = x64
3-
brave_electron_version = 6.0.9
3+
brave_electron_version = 6.1.0
44
chromedriver_version = 2.36
5-
target = v6.0.9
5+
target = v6.1.0
66
disturl=https://brave-laptop-binaries.s3.amazonaws.com/atom-shell/dist/
77
build_from_source = true

app/browser/api/ledger.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const format = require('date-fns/format')
99
const Immutable = require('immutable')
1010
const electron = require('electron')
1111
const ipc = electron.ipcMain
12+
const session = electron.session
1213
const path = require('path')
1314
const os = require('os')
1415
const qr = require('qr-image')
@@ -845,7 +846,9 @@ const shouldTrackTab = (state, tabId) => {
845846
if (tabFromState == null) {
846847
tabFromState = pageDataState.getLastClosedTab(state, tabId)
847848
}
848-
const isPrivate = !tabFromState.get('partition', '').startsWith('persist:') || tabFromState.get('incognito')
849+
const partition = tabFromState.get('partition', '')
850+
const ses = session.fromPartition(partition)
851+
const isPrivate = (ses && ses.isOffTheRecord()) || tabFromState.get('incognito')
849852
return !isPrivate && !tabFromState.isEmpty() && ledgerUtil.shouldTrackView(tabFromState)
850853
}
851854

app/browser/contentSettings/hostContentSettings.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,27 @@
33
* You can obtain one at http://mozilla.org/MPL/2.0/. */
44

55
const { makeImmutable } = require('../../common/state/immutableUtil')
6+
const appConfig = require('../../../js/constants/appConfig')
67

78
let registeredCallbacks = []
89
let registeredSessions = {}
910
let registeredPrivateSessions = {}
11+
const blockContentSetting = { setting: 'block', primaryPattern: '*' }
1012

1113
module.exports.setContentSettings = (contentSettings, incognito) => {
1214
contentSettings = makeImmutable(contentSettings)
1315

1416
const partitions = incognito ? registeredPrivateSessions : registeredSessions
1517
for (let partition in partitions) {
18+
let newContentSettings = contentSettings
19+
if (partition === appConfig.tor.partition) {
20+
// Do not allow plugins to be enabled in Tor contexts
21+
newContentSettings = contentSettings.set('plugins', makeImmutable([blockContentSetting]))
22+
}
23+
1624
const ses = partitions[partition]
1725

18-
contentSettings.forEach((settings, contentType) => {
26+
newContentSettings.forEach((settings, contentType) => {
1927
ses.contentSettings.clearForOneType(contentType)
2028
settings.forEach((setting) => {
2129
module.exports.setContentSetting(ses, setting.get('primaryPattern'), setting.get('secondaryPattern'),

app/browser/reducers/aboutNewTabReducer.js

+17-1
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ const aboutNewTabReducer = (state, action) => {
1414
switch (action.actionType) {
1515
case appConstants.APP_SET_STATE:
1616
const useAlternativePrivateSearchEngine = getSetting(settings.USE_ALTERNATIVE_PRIVATE_SEARCH_ENGINE, state.get('settings'))
17+
const torEnabled = getSetting(settings.USE_TOR_PRIVATE_TABS)
1718
state = aboutNewTabState.mergeDetails(state, {
1819
newTabPageDetail: {
19-
useAlternativePrivateSearchEngine
20+
useAlternativePrivateSearchEngine,
21+
torEnabled
2022
}
2123
})
2224
break
@@ -36,6 +38,20 @@ const aboutNewTabReducer = (state, action) => {
3638
useAlternativePrivateSearchEngine: action.value
3739
}
3840
})
41+
} else if (action.key === settings.USE_TOR_PRIVATE_TABS) {
42+
state = aboutNewTabState.mergeDetails(state, {
43+
newTabPageDetail: {
44+
torEnabled: action.value
45+
}
46+
})
47+
if (action.value === true) {
48+
// Also enable DDG
49+
state = aboutNewTabState.mergeDetails(state, {
50+
newTabPageDetail: {
51+
useAlternativePrivateSearchEngine: action.value
52+
}
53+
})
54+
}
3955
}
4056
}
4157
return state

app/browser/reducers/tabsReducer.js

+20-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const tabState = require('../../common/state/tabState')
1515
const windowState = require('../../common/state/windowState')
1616
const siteSettings = require('../../../js/state/siteSettings')
1717
const siteSettingsState = require('../../common/state/siteSettingsState')
18-
const {frameOptsFromFrame} = require('../../../js/state/frameStateUtil')
18+
const {frameOptsFromFrame, isTor} = require('../../../js/state/frameStateUtil')
1919
const updateState = require('../../common/state/updateState')
2020

2121
// Constants
@@ -51,6 +51,10 @@ const getWebRTCPolicy = (state, tabId) => {
5151
return webrtcConstants.default
5252
}
5353

54+
if (isTor(tabValue)) {
55+
return webrtcConstants.disableNonProxiedUdp
56+
}
57+
5458
const allSiteSettings = siteSettingsState.getAllSiteSettings(state, tabValue.get('incognito') === true)
5559
const tabSiteSettings =
5660
siteSettings.getSiteSettingsForURL(allSiteSettings, tabValue.get('url'))
@@ -248,6 +252,21 @@ const tabsReducer = (state, action, immutableAction) => {
248252
}
249253
})
250254
break
255+
case appConstants.APP_RECREATE_TOR_TAB:
256+
{
257+
const tabId = action.get('tabId')
258+
tabs.create({
259+
url: 'about:newtab',
260+
isPrivate: true,
261+
windowId: tabState.getWindowId(state, tabId),
262+
index: action.get('index'),
263+
active: true,
264+
isTor: action.get('torEnabled')
265+
}, (tab) => {
266+
appActions.tabCloseRequested(tabId)
267+
})
268+
break
269+
}
251270
case appConstants.APP_TAB_UPDATED:
252271
state = tabState.maybeCreateTab(state, action)
253272
// tabs.debugTabs(state)

app/browser/tabs.js

+30-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const { shouldDebugTabEvents } = require('../cmdLine')
99
const tabState = require('../common/state/tabState')
1010
const {app, extensions, session, ipcMain} = require('electron')
1111
const {makeImmutable, makeJS} = require('../common/state/immutableUtil')
12-
const {getTargetAboutUrl, getSourceAboutUrl, isSourceAboutUrl, newFrameUrl, isTargetAboutUrl, isIntermediateAboutPage, isTargetMagnetUrl, getSourceMagnetUrl} = require('../../js/lib/appUrlUtil')
12+
const {getExtensionsPath, getTargetAboutUrl, getSourceAboutUrl, isSourceAboutUrl, newFrameUrl, isTargetAboutUrl, isIntermediateAboutPage, isTargetMagnetUrl, getSourceMagnetUrl} = require('../../js/lib/appUrlUtil')
1313
const {isURL, getUrlFromInput, toPDFJSLocation, getDefaultFaviconUrl, isHttpOrHttps, getLocationIfPDF} = require('../../js/lib/urlutil')
1414
const {isSessionPartition} = require('../../js/state/frameStateUtil')
1515
const {getOrigin} = require('../../js/lib/urlutil')
@@ -28,7 +28,7 @@ const {newTabMode} = require('../common/constants/settingsEnums')
2828
const {tabCloseAction} = require('../common/constants/settingsEnums')
2929
const webContentsCache = require('./webContentsCache')
3030
const {FilterOptions} = require('ad-block')
31-
const {isResourceEnabled} = require('../filtering')
31+
const {isResourceEnabled, initPartition} = require('../filtering')
3232
const autofill = require('../autofill')
3333
const bookmarksState = require('../common/state/bookmarksState')
3434
const bookmarkFoldersState = require('../common/state/bookmarkFoldersState')
@@ -38,6 +38,8 @@ const bookmarkOrderCache = require('../common/cache/bookmarkOrderCache')
3838
const ledgerState = require('../common/state/ledgerState')
3939
const {getWindow, notifyWindowWebContentsAdded} = require('./windows')
4040
const activeTabHistory = require('./activeTabHistory')
41+
const path = require('path')
42+
const {getTorSocksProxy} = require('../channel')
4143

4244
let adBlockRegions
4345
let currentPartitionNumber = 0
@@ -101,6 +103,8 @@ const getPartition = (createProperties) => {
101103
let partition = session.defaultSession.partition
102104
if (createProperties.partition) {
103105
partition = createProperties.partition
106+
} else if (createProperties.isTor) {
107+
partition = appConfig.tor.partition
104108
} else if (createProperties.isPrivate) {
105109
partition = 'default'
106110
} else if (createProperties.isPartitioned) {
@@ -114,6 +118,7 @@ const getPartition = (createProperties) => {
114118

115119
const needsPartitionAssigned = (createProperties) => {
116120
return !createProperties.openerTabId ||
121+
createProperties.isTor ||
117122
createProperties.isPrivate ||
118123
createProperties.isPartitioned ||
119124
createProperties.partitionNumber ||
@@ -508,6 +513,12 @@ const api = {
508513
index = newTabValue.get('index')
509514
}
510515

516+
const ses = session.fromPartition(newTab.session.partition)
517+
let isPrivate
518+
if (ses) {
519+
isPrivate = ses.isOffTheRecord()
520+
}
521+
511522
const frameOpts = {
512523
location,
513524
displayURL,
@@ -516,6 +527,7 @@ const api = {
516527
active: !!newTabValue.get('active'),
517528
guestInstanceId: newTab.guestInstanceId,
518529
isPinned: !!newTabValue.get('pinned'),
530+
isPrivate,
519531
openerTabId,
520532
disposition,
521533
index,
@@ -1030,6 +1042,17 @@ const api = {
10301042
if (isSessionPartition(createProperties.partition)) {
10311043
createProperties.parent_partition = ''
10321044
}
1045+
if (createProperties.isTor) {
1046+
// TODO(riastradh): Duplicate logic in app/filtering.js.
1047+
createProperties.isolated_storage = true
1048+
createProperties.parent_partition = ''
1049+
createProperties.tor_proxy = getTorSocksProxy()
1050+
if (process.platform === 'win32') {
1051+
createProperties.tor_path = path.join(getExtensionsPath('bin'), 'tor.exe')
1052+
} else {
1053+
createProperties.tor_path = path.join(getExtensionsPath('bin'), 'tor')
1054+
}
1055+
}
10331056
}
10341057

10351058
// Tabs are allowed to be initially discarded (unloaded) if they are regular tabs
@@ -1051,6 +1074,11 @@ const api = {
10511074
}
10521075
extensions.createTab(createProperties, (tab) => {
10531076
cb && cb(tab)
1077+
// XXX: Workaround for 'browser-context-created' not emitted for Tor
1078+
// browsing context
1079+
if (createProperties.isTor) {
1080+
initPartition(appConfig.tor.partition)
1081+
}
10541082
})
10551083
}
10561084

app/channel.js

+31
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,34 @@ exports.getLinuxDesktopName = () => {
5252
}
5353
return desktopName
5454
}
55+
56+
// getTorSocksProxy()
57+
//
58+
// Return the socks5:// `URL' for the Tor socks proxy we will
59+
// configure the tor daemon to listen on and muon to connect to,
60+
// depending on which channel we're using. This is provisional
61+
// until we let the OS choose the port number as in
62+
// <https://github.com/brave/browser-laptop/issues/12936>, or
63+
// until we add support for local sockets for SOCKS proxies as in
64+
// <https://github.com/brave/muon/issues/469>.
65+
//
66+
exports.getTorSocksProxy = () => {
67+
let portno
68+
switch (channel) {
69+
case 'dev':
70+
case '':
71+
default:
72+
portno = 9250
73+
break
74+
case 'beta':
75+
portno = 9260
76+
break
77+
case 'nightly':
78+
portno = 9270
79+
break
80+
case 'developer':
81+
portno = 9280
82+
break
83+
}
84+
return `socks5://127.0.0.1:${portno}`
85+
}

app/common/commonMenu.js

+15-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const messages = require('../../js/constants/messages')
99
const locale = require('../../js/l10n')
1010
const settings = require('../../js/constants/settings')
1111
const {tabs} = require('../../js/constants/config')
12-
const getSetting = require('../../js/settings').getSetting
12+
const {getSetting} = require('../../js/settings')
1313
const communityURL = 'https://community.brave.com/'
1414
const isDarwin = process.platform === 'darwin'
1515
const electron = require('electron')
@@ -77,10 +77,20 @@ module.exports.newPrivateTabMenuItem = () => {
7777
label: locale.translation('newPrivateTab'),
7878
accelerator: 'Shift+CmdOrCtrl+P',
7979
click: function (item, focusedWindow) {
80-
ensureAtLeastOneWindow({
81-
url: 'about:newtab',
82-
isPrivate: true
83-
})
80+
// Check if Tor is available
81+
const useTor = getSetting(settings.USE_TOR_PRIVATE_TABS)
82+
if (useTor) {
83+
ensureAtLeastOneWindow({
84+
url: 'about:newtab',
85+
isPrivate: true,
86+
isTor: true
87+
})
88+
} else {
89+
ensureAtLeastOneWindow({
90+
url: 'about:newtab',
91+
isPrivate: true
92+
})
93+
}
8494
}
8595
}
8696
}

app/common/lib/suggestion.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ const sigmoid = (t) => {
2525

2626
const ONE_DAY = 1000 * 60 * 60 * 24
2727

28+
const searchSuggestionsEnabled = (state, tabId) => {
29+
const frame = getFrameByTabId(state, tabId)
30+
if (!frame || frame.get('isPrivate')) {
31+
return false
32+
}
33+
return getSetting(settings.OFFER_SEARCH_SUGGESTIONS)
34+
}
35+
2836
/*
2937
* Calculate the sorting priority for a history item based on number of
3038
* accesses and time since last access
@@ -564,7 +572,7 @@ const getSearchSuggestions = (state, tabId, urlLocationLower) => {
564572
return new Promise((resolve, reject) => {
565573
const mapListToElements = getMapListToElements(urlLocationLower)
566574
let suggestionsList = Immutable.List()
567-
if (getSetting(settings.OFFER_SEARCH_SUGGESTIONS)) {
575+
if (searchSuggestionsEnabled(state, tabId)) {
568576
const searchResults = state.get('searchResults')
569577
const sortHandler = getSortForSearchSuggestions(urlLocationLower)
570578
if (searchResults) {
@@ -630,7 +638,7 @@ const generateNewSearchXHRResults = debounce((state, windowId, tabId, input) =>
630638
? frameSearchDetail.get('autocomplete')
631639
: searchDetail.get('autocompleteURL')
632640

633-
const shouldDoSearchSuggestions = getSetting(settings.OFFER_SEARCH_SUGGESTIONS) &&
641+
const shouldDoSearchSuggestions = searchSuggestionsEnabled(state, tabId) &&
634642
autocompleteURL &&
635643
!isUrl(input) &&
636644
input.length !== 0

app/extensions.js

+17-1
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,22 @@ let generateBraveManifest = () => {
128128
'content/scripts/themeColor.js'
129129
]
130130
},
131+
{
132+
run_at: 'document_end',
133+
all_frames: false,
134+
matches: ['<all_urls>'],
135+
include_globs: [
136+
'http://*/*', 'https://*/*'
137+
],
138+
exclude_globs: [
139+
indexHTML,
140+
getBraveExtUrl('about-*.html'),
141+
getBraveExtUrl('about-*.html') + '#*'
142+
],
143+
js: [
144+
'content/scripts/favicon.js'
145+
]
146+
},
131147
{
132148
run_at: 'document_start',
133149
js: [
@@ -273,7 +289,7 @@ let generateTorrentManifest = () => {
273289
48: 'img/webtorrent-48.png',
274290
16: 'img/webtorrent-16.png'
275291
},
276-
incognito: 'split',
292+
incognito: 'not_allowed',
277293
key: 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyWl+wMvL0wZX3JUs7GeZAvxMP+LWEh2bwMV1HyuBra/lGZIq3Fmh0+AFnvFPXz1NpQkbLS3QWyqhdIn/lepGwuc2ma0glPzzmieqwctUurMGSGManApGO1MkcbSPhb+R1mx8tMam5+wbme4WoW37PI3oATgOs2NvHYuP60qol3U7b/zB3IWuqtwtqKe2Q1xY17btvPuz148ygWWIHneedt0jwfr6Zp+CSLARB9Heq/jqGXV4dPSVZ5ebBHLQ452iZkHxS6fm4Z+IxjKdYs3HNj/s8xbfEZ2ydnArGdJ0lpSK9jkDGYyUBugq5Qp3FH6zV89WqBvoV1dqUmL9gxbHsQIDAQAB'
278294
}
279295
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const getBase64FromImageUrl = (url) => {
2+
return new Promise((resolve, reject) => {
3+
const img = new window.Image()
4+
img.onerror = function () {
5+
reject(new Error('unable to load image'))
6+
}
7+
img.onload = function () {
8+
const canvas = document.createElement('canvas')
9+
canvas.width = this.naturalWidth
10+
canvas.height = this.naturalHeight
11+
canvas.getContext('2d')
12+
.drawImage(this, 0, 0)
13+
resolve(canvas.toDataURL('image/png'))
14+
}
15+
img.src = url
16+
})
17+
}
18+
19+
let faviconUrl = window.location.origin + '/favicon.ico'
20+
const faviconNode = document.head.querySelector("link[rel='icon']") || document.head.querySelector("link[rel='shortcut icon']")
21+
if (faviconNode) {
22+
faviconUrl = faviconNode.getAttribute('href') || faviconUrl
23+
}
24+
25+
getBase64FromImageUrl(faviconUrl).then((data) => {
26+
chrome.ipcRenderer.sendToHost('got-page-favicon', data)
27+
})

0 commit comments

Comments
 (0)