enabled: false
}
}
+ },
+ tracker: {
+ enabled: true
}
}
private videoCategories: Array<VideoConstant<number>> = []
import { Component, OnInit } from '@angular/core'
import { ServerService } from '@app/core'
import { I18n } from '@ngx-translate/i18n-polyfill'
-import { ServerConfig } from '../../../../../shared'
@Component({
selector: 'my-instance-features-table',
{
label: this.i18n('Torrent import'),
value: config.import.videos.torrent.enabled
+ },
+ {
+ label: this.i18n('P2P enabled'),
+ value: config.tracker.enabled
}
]
}
// If the view is not expanded, take into account the menu
.privacy-concerns {
width: calc(100% - #{$menu-width});
+ margin-left: -15px;
}
@media screen and (max-width: $small-view) {
import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
import { Video } from '@app/shared/video/video.model'
+import { isWebRTCDisabled } from '../../../assets/player/utils'
@Component({
selector: 'my-video-watch',
private currentTime: number
private paramsSub: Subscription
private queryParamsSub: Subscription
+ private configSub: Subscription
constructor (
private elementRef: ElementRef,
}
ngOnInit () {
- if (
- !!((window as any).RTCPeerConnection || (window as any).mozRTCPeerConnection || (window as any).webkitRTCPeerConnection) === false ||
- peertubeLocalStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY) === 'true'
- ) {
- this.hasAlreadyAcceptedPrivacyConcern = true
- }
+ this.configSub = this.serverService.configLoaded
+ .subscribe(() => {
+ if (
+ isWebRTCDisabled() ||
+ this.serverService.getConfig().tracker.enabled === false ||
+ peertubeLocalStorage.getItem(VideoWatchComponent.LOCAL_STORAGE_PRIVACY_CONCERN_KEY) === 'true'
+ ) {
+ this.hasAlreadyAcceptedPrivacyConcern = true
+ }
+ })
this.paramsSub = this.route.params.subscribe(routeParams => {
const videoId = routeParams[ 'videoId' ]
return str.charAt(0).toUpperCase() + str.slice(1)
}
+function isWebRTCDisabled () {
+ return !!((window as any).RTCPeerConnection || (window as any).mozRTCPeerConnection || (window as any).webkitRTCPeerConnection) === false
+}
+
// https://github.com/danrevah/ngx-pipes/blob/master/src/pipes/math/bytes.ts
// Don't import all Angular stuff, just copy the code with shame
const dictionaryBytes: Array<{max: number, type: string}> = [
toTitleCase,
timeToInt,
secondsToTime,
+ isWebRTCDisabled,
buildVideoLink,
buildVideoEmbed,
videoFileMaxByResolution,
.vjs-dock-description {
font-size: 11px;
- &::before, &::after {
+ .text::before, .text::after {
display: inline-block;
content: '\1F308';
}
- &::before {
+ .text::before {
margin-right: 4px;
}
- &::after {
+ .text::after {
margin-left: 4px;
transform: scale(-1, 1);
}
import * as Channel from 'jschannel'
-import { peertubeTranslate, ResultList, VideoDetails } from '../../../../shared'
+import { peertubeTranslate, ResultList, ServerConfig, VideoDetails } from '../../../../shared'
import { PeerTubeResolution } from '../player/definitions'
import { VideoJSCaption } from '../../assets/player/peertube-videojs-typings'
import { VideoCaption } from '../../../../shared/models/videos/caption/video-caption.model'
return fetch(this.getVideoUrl(videoId) + '/captions')
}
+ loadConfig (): Promise<Response> {
+ return fetch('/api/v1/config')
+ }
+
removeElement (element: HTMLElement) {
element.parentElement.removeChild(element)
}
try {
const params = new URL(window.location.toString()).searchParams
- this.autoplay = this.getParamToggle(params, 'autoplay')
- this.controls = this.getParamToggle(params, 'controls')
- this.muted = this.getParamToggle(params, 'muted')
- this.loop = this.getParamToggle(params, 'loop')
+ this.autoplay = this.getParamToggle(params, 'autoplay', false)
+ this.controls = this.getParamToggle(params, 'controls', true)
+ this.muted = this.getParamToggle(params, 'muted', false)
+ this.loop = this.getParamToggle(params, 'loop', false)
this.enableApi = this.getParamToggle(params, 'api', this.enableApi)
this.scope = this.getParamString(params, 'scope', this.scope)
const urlParts = window.location.pathname.split('/')
const videoId = urlParts[ urlParts.length - 1 ]
- const [ serverTranslations, videoResponse, captionsResponse ] = await Promise.all([
+ const [ serverTranslations, videoResponse, captionsResponse, configResponse ] = await Promise.all([
PeertubePlayerManager.getServerTranslations(window.location.origin, navigator.language),
this.loadVideoInfo(videoId),
- this.loadVideoCaptions(videoId)
+ this.loadVideoCaptions(videoId),
+ this.loadConfig()
])
if (!videoResponse.ok) {
window[ 'videojsPlayer' ] = this.player
if (this.controls) {
+ const config: ServerConfig = await configResponse.json()
+ const description = config.tracker.enabled
+ ? '<span class="text">' + this.player.localize('Uses P2P, others may know your IP is downloading this video.') + '</span>'
+ : undefined
+
this.player.dock({
title: videoInfo.name,
- description: this.player.localize('Uses P2P, others may know your IP is downloading this video.')
+ description
})
}
report_only: true # CSP directives are still being tested, so disable the report only mode at your own risk!
report_uri:
+tracker:
+ # If you disable the tracker, you disable the P2P aspect of PeerTube
+ enabled: true
+ # Only handle requests on your videos.
+ # If you set this to false it means you have a public tracker.
+ # Then, it is possible that clients overload your instance with external torrents
+ private: true
+ # Reject peers that do a lot of announces (could improve privacy of TCP/UDP peers)
+ reject_too_many_announces: false
+
cache:
previews:
size: 500 # Max number of previews you want to cache
report_only: true # CSP directives are still being tested, so disable the report only mode at your own risk!
report_uri:
+tracker:
+ # If you disable the tracker, you disable the P2P aspect of PeerTube
+ enabled: true
+ # Only handle requests on your videos.
+ # If you set this to false it means you have a public tracker.
+ # Then, it is possible that clients overload your instance with external torrents
+ private: true
+ # Reject peers that do a lot of announces (could improve privacy of TCP/UDP peers)
+ reject_too_many_announces: false
+
###############################################################################
#
videos: {
intervalDays: CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS
}
+ },
+ tracker: {
+ enabled: CONFIG.TRACKER.ENABLED
}
}
ws: false,
dht: false,
filter: async function (infoHash, params, cb) {
+ if (CONFIG.TRACKER.ENABLED === false) {
+ return cb(new Error('Tracker is disabled on this instance.'))
+ }
+
let ip: string
if (params.type === 'ws') {
peersIps[ ip ] = peersIps[ ip ] ? peersIps[ ip ] + 1 : 1
peersIpInfoHash[ key ] = peersIpInfoHash[ key ] ? peersIpInfoHash[ key ] + 1 : 1
- if (peersIpInfoHash[ key ] > TRACKER_RATE_LIMITS.ANNOUNCES_PER_IP_PER_INFOHASH) {
+ if (CONFIG.TRACKER.REJECT_TOO_MANY_ANNOUNCES && peersIpInfoHash[ key ] > TRACKER_RATE_LIMITS.ANNOUNCES_PER_IP_PER_INFOHASH) {
return cb(new Error(`Too many requests (${peersIpInfoHash[ key ]} of ip ${ip} for torrent ${infoHash}`))
}
try {
+ if (CONFIG.TRACKER.PRIVATE === false) return cb()
+
const videoFileExists = await VideoFileModel.doesInfohashExist(infoHash)
if (videoFileExists === true) return cb()
}
})
-trackerServer.on('error', function (err) {
- logger.error('Error in tracker.', { err })
-})
+if (CONFIG.TRACKER.ENABLED !== false) {
-trackerServer.on('warning', function (err) {
- logger.warn('Warning in tracker.', { err })
-})
+ trackerServer.on('error', function (err) {
+ logger.error('Error in tracker.', { err })
+ })
+
+ trackerServer.on('warning', function (err) {
+ logger.warn('Warning in tracker.', { err })
+ })
+}
const onHttpRequest = trackerServer.onHttpRequest.bind(trackerServer)
trackerRouter.get('/tracker/announce', (req, res) => onHttpRequest(req, res, { action: 'announce' }))
'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route',
'instance.is_nsfw', 'instance.default_nsfw_policy', 'instance.robots', 'instance.securitytxt',
'services.twitter.username', 'services.twitter.whitelisted',
- 'followers.instance.enabled', 'followers.instance.manual_approval'
+ 'followers.instance.enabled', 'followers.instance.manual_approval',
+ 'tracker.enabled', 'tracker.private', 'tracker.reject_too_many_announces'
]
const requiredAlternatives = [
[ // set
REPORT_ONLY: config.get<boolean>('csp.report_only'),
REPORT_URI: config.get<boolean>('csp.report_uri')
},
+ TRACKER: {
+ ENABLED: config.get<boolean>('tracker.enabled'),
+ PRIVATE: config.get<boolean>('tracker.private'),
+ REJECT_TOO_MANY_ANNOUNCES: config.get<boolean>('tracker.reject_too_many_announces')
+ },
ADMIN: {
get EMAIL () { return config.get<string>('admin.email') }
},
import * as magnetUtil from 'magnet-uri'
import 'mocha'
-import { getVideo, killallServers, runServer, ServerInfo, uploadVideo } from '../../../../shared/utils'
+import { getVideo, killallServers, reRunServer, runServer, ServerInfo, uploadVideo } from '../../../../shared/utils'
import { flushTests, setAccessTokensToServers } from '../../../../shared/utils/index'
import { VideoDetails } from '../../../../shared/models/videos'
import * as WebTorrent from 'webtorrent'
}
})
- it('Should return an error when adding an incorrect infohash', done => {
+ it('Should return an error when adding an incorrect infohash', function (done) {
this.timeout(10000)
const webtorrent = new WebTorrent()
torrent.on('done', () => done(new Error('No error on infohash')))
})
- it('Should succeed with the correct infohash', done => {
+ it('Should succeed with the correct infohash', function (done) {
this.timeout(10000)
const webtorrent = new WebTorrent()
torrent.on('done', done)
})
+ it('Should disable the tracker', function (done) {
+ this.timeout(20000)
+
+ killallServers([ server ])
+ reRunServer(server, { tracker: { enabled: false } })
+ .then(() => {
+ const webtorrent = new WebTorrent()
+
+ const torrent = webtorrent.add(goodMagnet)
+
+ torrent.on('error', done)
+ torrent.on('warning', warn => {
+ const message = typeof warn === 'string' ? warn : warn.message
+ if (message.indexOf('disabled ') !== -1) return done()
+ })
+
+ torrent.on('done', () => done(new Error('Tracker is enabled')))
+ })
+ })
+
after(async function () {
killallServers([ server ])
})
intervalDays: number
}
}
+
+ tracker: {
+ enabled: boolean
+ }
}
log:
level: 'info' # debug/info/warning/error
+tracker:
+ enabled: true
+ reject_too_many_announces: false # false because we have issues with traefik and ws ip/port forwarding
+
admin:
email: null