aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2017-12-21 09:56:59 +0100
committerChocobozzz <me@florianbigard.com>2017-12-21 09:56:59 +0100
commit225a89c2afbbe53cf39ffa7ea0cd485095a1d5f5 (patch)
tree9dc8fa039e820229fd3ecb386d6f63bf02e16698
parent6725d05c5f71e0cdf0deba6692220b73e42e7ffa (diff)
downloadPeerTube-225a89c2afbbe53cf39ffa7ea0cd485095a1d5f5.tar.gz
PeerTube-225a89c2afbbe53cf39ffa7ea0cd485095a1d5f5.tar.zst
PeerTube-225a89c2afbbe53cf39ffa7ea0cd485095a1d5f5.zip
Sanitize url to not end with implicit ports
-rw-r--r--server/controllers/api/server/follows.ts24
-rw-r--r--server/helpers/core-utils.ts22
-rw-r--r--server/helpers/custom-validators/webfinger.ts5
-rw-r--r--server/initializers/constants.ts87
-rw-r--r--server/initializers/migrations/0140-actor-url.ts42
5 files changed, 122 insertions, 58 deletions
diff --git a/server/controllers/api/server/follows.ts b/server/controllers/api/server/follows.ts
index e7d81f7c3..ae5413b75 100644
--- a/server/controllers/api/server/follows.ts
+++ b/server/controllers/api/server/follows.ts
@@ -1,19 +1,15 @@
1import * as express from 'express' 1import * as express from 'express'
2import { UserRight } from '../../../../shared/models/users' 2import { UserRight } from '../../../../shared/models/users'
3import { getFormattedObjects, getServerActor, loadActorUrlOrGetFromWebfinger, logger, retryTransactionWrapper } from '../../../helpers' 3import {
4import { sequelizeTypescript, SERVER_ACTOR_NAME } from '../../../initializers' 4 getFormattedObjects, getServerActor, loadActorUrlOrGetFromWebfinger, logger, retryTransactionWrapper,
5 sanitizeHost
6} from '../../../helpers'
7import { REMOTE_SCHEME, sequelizeTypescript, SERVER_ACTOR_NAME } from '../../../initializers'
5import { getOrCreateActorAndServerAndModel } from '../../../lib/activitypub' 8import { getOrCreateActorAndServerAndModel } from '../../../lib/activitypub'
6import { sendFollow, sendUndoFollow } from '../../../lib/activitypub/send' 9import { sendFollow, sendUndoFollow } from '../../../lib/activitypub/send'
7import { 10import {
8 asyncMiddleware, 11 asyncMiddleware, authenticate, ensureUserHasRight, paginationValidator, removeFollowingValidator, setBodyHostsPort,
9 authenticate, 12 setFollowersSort, setFollowingSort, setPagination
10 ensureUserHasRight,
11 paginationValidator,
12 removeFollowingValidator,
13 setBodyHostsPort,
14 setFollowersSort,
15 setFollowingSort,
16 setPagination
17} from '../../../middlewares' 13} from '../../../middlewares'
18import { followersSortValidator, followingSortValidator, followValidator } from '../../../middlewares/validators' 14import { followersSortValidator, followingSortValidator, followValidator } from '../../../middlewares/validators'
19import { ActorModel } from '../../../models/activitypub/actor' 15import { ActorModel } from '../../../models/activitypub/actor'
@@ -82,10 +78,12 @@ async function followRetry (req: express.Request, res: express.Response, next: e
82 const actorName = SERVER_ACTOR_NAME 78 const actorName = SERVER_ACTOR_NAME
83 79
84 for (const host of hosts) { 80 for (const host of hosts) {
81 const sanitizedHost = sanitizeHost(host, REMOTE_SCHEME.HTTP)
82
85 // We process each host in a specific transaction 83 // We process each host in a specific transaction
86 // First, we add the follow request in the database 84 // First, we add the follow request in the database
87 // Then we send the follow request to other actor 85 // Then we send the follow request to other actor
88 const p = loadActorUrlOrGetFromWebfinger(actorName, host) 86 const p = loadActorUrlOrGetFromWebfinger(actorName, sanitizedHost)
89 .then(actorUrl => getOrCreateActorAndServerAndModel(actorUrl)) 87 .then(actorUrl => getOrCreateActorAndServerAndModel(actorUrl))
90 .then(targetActor => { 88 .then(targetActor => {
91 const options = { 89 const options = {
@@ -95,7 +93,7 @@ async function followRetry (req: express.Request, res: express.Response, next: e
95 93
96 return retryTransactionWrapper(follow, options) 94 return retryTransactionWrapper(follow, options)
97 }) 95 })
98 .catch(err => logger.warn('Cannot follow server %s.', host, err)) 96 .catch(err => logger.warn('Cannot follow server %s.', sanitizedHost, err))
99 97
100 tasks.push(p) 98 tasks.push(p)
101 } 99 }
diff --git a/server/helpers/core-utils.ts b/server/helpers/core-utils.ts
index 443115336..0c6c36d11 100644
--- a/server/helpers/core-utils.ts
+++ b/server/helpers/core-utils.ts
@@ -11,6 +11,26 @@ import * as mkdirp from 'mkdirp'
11import { join } from 'path' 11import { join } from 'path'
12import * as pem from 'pem' 12import * as pem from 'pem'
13import * as rimraf from 'rimraf' 13import * as rimraf from 'rimraf'
14import { URL } from 'url'
15
16function sanitizeUrl (url: string) {
17 const urlObject = new URL(url)
18
19 if (urlObject.protocol === 'https:' && urlObject.port === '443') {
20 urlObject.port = ''
21 } else if (urlObject.protocol === 'http:' && urlObject.port === '80') {
22 urlObject.port = ''
23 }
24
25 return urlObject.href.replace(/\/$/, '')
26}
27
28// Don't import remote scheme from constants because we are in core utils
29function sanitizeHost (host: string, remoteScheme: string) {
30 let toRemove = remoteScheme === 'https' ? 443 : 80
31
32 return host.replace(new RegExp(`:${toRemove}$`), '')
33}
14 34
15function isTestInstance () { 35function isTestInstance () {
16 return process.env.NODE_ENV === 'test' 36 return process.env.NODE_ENV === 'test'
@@ -114,6 +134,8 @@ export {
114 root, 134 root,
115 escapeHTML, 135 escapeHTML,
116 pageToStartAndCount, 136 pageToStartAndCount,
137 sanitizeUrl,
138 sanitizeHost,
117 139
118 promisify0, 140 promisify0,
119 promisify1, 141 promisify1,
diff --git a/server/helpers/custom-validators/webfinger.ts b/server/helpers/custom-validators/webfinger.ts
index 1b9aad444..46f1ac210 100644
--- a/server/helpers/custom-validators/webfinger.ts
+++ b/server/helpers/custom-validators/webfinger.ts
@@ -1,4 +1,5 @@
1import { CONFIG } from '../../initializers' 1import { CONFIG, REMOTE_SCHEME } from '../../initializers'
2import { sanitizeHost } from '../core-utils'
2import { exists } from './misc' 3import { exists } from './misc'
3 4
4function isWebfingerResourceValid (value: string) { 5function isWebfingerResourceValid (value: string) {
@@ -11,7 +12,7 @@ function isWebfingerResourceValid (value: string) {
11 12
12 const host = actorParts[1] 13 const host = actorParts[1]
13 14
14 return host === CONFIG.WEBSERVER.HOSTNAME || host === CONFIG.WEBSERVER.HOST 15 return sanitizeHost(host, REMOTE_SCHEME.HTTP) === CONFIG.WEBSERVER.HOSTNAME
15} 16}
16 17
17// --------------------------------------------------------------------------- 18// ---------------------------------------------------------------------------
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index 2ea2aa6b9..100a77622 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -1,15 +1,15 @@
1import * as config from 'config' 1import * as config from 'config'
2import { join } from 'path' 2import { join } from 'path'
3import { JobCategory, JobState, VideoRateType } from '../../shared/models' 3import { JobCategory, JobState, VideoRateType } from '../../shared/models'
4import { FollowState } from '../../shared/models/actors'
5import { ActivityPubActorType } from '../../shared/models/activitypub' 4import { ActivityPubActorType } from '../../shared/models/activitypub'
5import { FollowState } from '../../shared/models/actors'
6import { VideoPrivacy } from '../../shared/models/videos' 6import { VideoPrivacy } from '../../shared/models/videos'
7// Do not use barrels, remain constants as independent as possible 7// Do not use barrels, remain constants as independent as possible
8import { isTestInstance, root } from '../helpers/core-utils' 8import { isTestInstance, root, sanitizeHost, sanitizeUrl } from '../helpers/core-utils'
9 9
10// --------------------------------------------------------------------------- 10// ---------------------------------------------------------------------------
11 11
12const LAST_MIGRATION_VERSION = 135 12const LAST_MIGRATION_VERSION = 140
13 13
14// --------------------------------------------------------------------------- 14// ---------------------------------------------------------------------------
15 15
@@ -38,6 +38,44 @@ const OAUTH_LIFETIME = {
38 38
39// --------------------------------------------------------------------------- 39// ---------------------------------------------------------------------------
40 40
41// Number of points we add/remove from a friend after a successful/bad request
42const SERVERS_SCORE = {
43 PENALTY: -10,
44 BONUS: 10,
45 BASE: 100,
46 MAX: 1000
47}
48
49const FOLLOW_STATES: { [ id: string ]: FollowState } = {
50 PENDING: 'pending',
51 ACCEPTED: 'accepted'
52}
53
54const REMOTE_SCHEME = {
55 HTTP: 'https',
56 WS: 'wss'
57}
58
59const JOB_STATES: { [ id: string ]: JobState } = {
60 PENDING: 'pending',
61 PROCESSING: 'processing',
62 ERROR: 'error',
63 SUCCESS: 'success'
64}
65const JOB_CATEGORIES: { [ id: string ]: JobCategory } = {
66 TRANSCODING: 'transcoding',
67 ACTIVITYPUB_HTTP: 'activitypub-http'
68}
69// How many maximum jobs we fetch from the database per cycle
70const JOBS_FETCH_LIMIT_PER_CYCLE = {
71 transcoding: 10,
72 httpRequest: 20
73}
74// 1 minutes
75let JOBS_FETCHING_INTERVAL = 60000
76
77// ---------------------------------------------------------------------------
78
41const CONFIG = { 79const CONFIG = {
42 LISTEN: { 80 LISTEN: {
43 PORT: config.get<number>('listen.port') 81 PORT: config.get<number>('listen.port')
@@ -93,8 +131,6 @@ const CONFIG = {
93 } 131 }
94 } 132 }
95} 133}
96CONFIG.WEBSERVER.URL = CONFIG.WEBSERVER.SCHEME + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT
97CONFIG.WEBSERVER.HOST = CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT
98 134
99const AVATARS_DIR = { 135const AVATARS_DIR = {
100 ACCOUNT: join(CONFIG.STORAGE.AVATARS_DIR, 'account') 136 ACCOUNT: join(CONFIG.STORAGE.AVATARS_DIR, 'account')
@@ -238,44 +274,6 @@ const ACTIVITY_PUB_ACTOR_TYPES: { [ id: string ]: ActivityPubActorType } = {
238 274
239// --------------------------------------------------------------------------- 275// ---------------------------------------------------------------------------
240 276
241// Number of points we add/remove from a friend after a successful/bad request
242const SERVERS_SCORE = {
243 PENALTY: -10,
244 BONUS: 10,
245 BASE: 100,
246 MAX: 1000
247}
248
249const FOLLOW_STATES: { [ id: string ]: FollowState } = {
250 PENDING: 'pending',
251 ACCEPTED: 'accepted'
252}
253
254const REMOTE_SCHEME = {
255 HTTP: 'https',
256 WS: 'wss'
257}
258
259const JOB_STATES: { [ id: string ]: JobState } = {
260 PENDING: 'pending',
261 PROCESSING: 'processing',
262 ERROR: 'error',
263 SUCCESS: 'success'
264}
265const JOB_CATEGORIES: { [ id: string ]: JobCategory } = {
266 TRANSCODING: 'transcoding',
267 ACTIVITYPUB_HTTP: 'activitypub-http'
268}
269// How many maximum jobs we fetch from the database per cycle
270const JOBS_FETCH_LIMIT_PER_CYCLE = {
271 transcoding: 10,
272 httpRequest: 20
273}
274// 1 minutes
275let JOBS_FETCHING_INTERVAL = 60000
276
277// ---------------------------------------------------------------------------
278
279const PRIVATE_RSA_KEY_SIZE = 2048 277const PRIVATE_RSA_KEY_SIZE = 2048
280 278
281// Password encryption 279// Password encryption
@@ -334,6 +332,9 @@ if (isTestInstance() === true) {
334 ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE = 2 332 ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE = 2
335} 333}
336 334
335CONFIG.WEBSERVER.URL = sanitizeUrl(CONFIG.WEBSERVER.SCHEME + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT)
336CONFIG.WEBSERVER.HOST = sanitizeHost(CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT, REMOTE_SCHEME.HTTP)
337
337// --------------------------------------------------------------------------- 338// ---------------------------------------------------------------------------
338 339
339export { 340export {
diff --git a/server/initializers/migrations/0140-actor-url.ts b/server/initializers/migrations/0140-actor-url.ts
new file mode 100644
index 000000000..626f3c444
--- /dev/null
+++ b/server/initializers/migrations/0140-actor-url.ts
@@ -0,0 +1,42 @@
1import * as Sequelize from 'sequelize'
2import { DataType } from 'sequelize-typescript'
3import { createPrivateAndPublicKeys } from '../../helpers'
4import { CONFIG } from '../constants'
5
6async function up (utils: {
7 transaction: Sequelize.Transaction,
8 queryInterface: Sequelize.QueryInterface,
9 sequelize: Sequelize.Sequelize
10}): Promise<void> {
11 const toReplace = CONFIG.WEBSERVER.HOSTNAME + ':443'
12 const by = CONFIG.WEBSERVER.HOST
13 const replacer = column => `replace("${column}", '${toReplace}', '${by}')`
14
15 {
16 const query = `UPDATE video SET url = ${replacer('url')}`
17 await utils.sequelize.query(query)
18 }
19
20 {
21 const query = `
22 UPDATE actor SET url = ${replacer('url')}, "inboxUrl" = ${replacer('inboxUrl')}, "outboxUrl" = ${replacer('outboxUrl')},
23 "sharedInboxUrl" = ${replacer('sharedInboxUrl')}, "followersUrl" = ${replacer('followersUrl')},
24 "followingUrl" = ${replacer('followingUrl')}
25 `
26 await utils.sequelize.query(query)
27 }
28
29 {
30 const query = `UPDATE server SET host = replace(host, ':443', '')`
31 await utils.sequelize.query(query)
32 }
33}
34
35function down (options) {
36 throw new Error('Not implemented.')
37}
38
39export {
40 up,
41 down
42}