aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib
diff options
context:
space:
mode:
Diffstat (limited to 'server/lib')
-rw-r--r--server/lib/activitypub/actors/get.ts2
-rw-r--r--server/lib/activitypub/actors/index.ts1
-rw-r--r--server/lib/activitypub/actors/refresh.ts4
-rw-r--r--server/lib/activitypub/actors/shared/index.ts2
-rw-r--r--server/lib/activitypub/actors/webfinger.ts67
-rw-r--r--server/lib/activitypub/videos/get.ts2
-rw-r--r--server/lib/activitypub/videos/refresh.ts2
-rw-r--r--server/lib/job-queue/handlers/activitypub-follow.ts3
-rw-r--r--server/lib/job-queue/handlers/activitypub-refresher.ts2
-rw-r--r--server/lib/model-loaders/actor.ts16
-rw-r--r--server/lib/model-loaders/index.ts2
-rw-r--r--server/lib/model-loaders/video.ts64
-rw-r--r--server/lib/server-config-manager.ts2
-rw-r--r--server/lib/signup.ts62
14 files changed, 221 insertions, 10 deletions
diff --git a/server/lib/activitypub/actors/get.ts b/server/lib/activitypub/actors/get.ts
index 0d5bea789..e7e87a967 100644
--- a/server/lib/activitypub/actors/get.ts
+++ b/server/lib/activitypub/actors/get.ts
@@ -1,9 +1,9 @@
1 1
2import { checkUrlsSameHost, getAPId } from '@server/helpers/activitypub' 2import { checkUrlsSameHost, getAPId } from '@server/helpers/activitypub'
3import { ActorFetchByUrlType, fetchActorByUrl } from '@server/helpers/actor'
4import { retryTransactionWrapper } from '@server/helpers/database-utils' 3import { retryTransactionWrapper } from '@server/helpers/database-utils'
5import { logger } from '@server/helpers/logger' 4import { logger } from '@server/helpers/logger'
6import { JobQueue } from '@server/lib/job-queue' 5import { JobQueue } from '@server/lib/job-queue'
6import { ActorFetchByUrlType, fetchActorByUrl } from '@server/lib/model-loaders'
7import { MActor, MActorAccountChannelId, MActorAccountChannelIdActor, MActorAccountId, MActorFullActor } from '@server/types/models' 7import { MActor, MActorAccountChannelId, MActorAccountChannelIdActor, MActorAccountId, MActorFullActor } from '@server/types/models'
8import { ActivityPubActor } from '@shared/models' 8import { ActivityPubActor } from '@shared/models'
9import { refreshActorIfNeeded } from './refresh' 9import { refreshActorIfNeeded } from './refresh'
diff --git a/server/lib/activitypub/actors/index.ts b/server/lib/activitypub/actors/index.ts
index a54da6798..5ee2a6f1a 100644
--- a/server/lib/activitypub/actors/index.ts
+++ b/server/lib/activitypub/actors/index.ts
@@ -3,3 +3,4 @@ export * from './image'
3export * from './keys' 3export * from './keys'
4export * from './refresh' 4export * from './refresh'
5export * from './updater' 5export * from './updater'
6export * from './webfinger'
diff --git a/server/lib/activitypub/actors/refresh.ts b/server/lib/activitypub/actors/refresh.ts
index ff3b249d0..9f2289bfa 100644
--- a/server/lib/activitypub/actors/refresh.ts
+++ b/server/lib/activitypub/actors/refresh.ts
@@ -1,12 +1,12 @@
1import { ActorFetchByUrlType } from '@server/helpers/actor'
2import { logger } from '@server/helpers/logger' 1import { logger } from '@server/helpers/logger'
3import { PeerTubeRequestError } from '@server/helpers/requests' 2import { PeerTubeRequestError } from '@server/helpers/requests'
4import { getUrlFromWebfinger } from '@server/helpers/webfinger' 3import { ActorFetchByUrlType } from '@server/lib/model-loaders'
5import { ActorModel } from '@server/models/actor/actor' 4import { ActorModel } from '@server/models/actor/actor'
6import { MActorAccountChannelId, MActorFull } from '@server/types/models' 5import { MActorAccountChannelId, MActorFull } from '@server/types/models'
7import { HttpStatusCode } from '@shared/core-utils' 6import { HttpStatusCode } from '@shared/core-utils'
8import { fetchRemoteActor } from './shared' 7import { fetchRemoteActor } from './shared'
9import { APActorUpdater } from './updater' 8import { APActorUpdater } from './updater'
9import { getUrlFromWebfinger } from './webfinger'
10 10
11async function refreshActorIfNeeded <T extends MActorFull | MActorAccountChannelId> ( 11async function refreshActorIfNeeded <T extends MActorFull | MActorAccountChannelId> (
12 actorArg: T, 12 actorArg: T,
diff --git a/server/lib/activitypub/actors/shared/index.ts b/server/lib/activitypub/actors/shared/index.ts
index a2ff468cf..52af1a8e1 100644
--- a/server/lib/activitypub/actors/shared/index.ts
+++ b/server/lib/activitypub/actors/shared/index.ts
@@ -1,3 +1,3 @@
1export * from './creator' 1export * from './creator'
2export * from './url-to-object'
3export * from './object-to-model-attributes' 2export * from './object-to-model-attributes'
3export * from './url-to-object'
diff --git a/server/lib/activitypub/actors/webfinger.ts b/server/lib/activitypub/actors/webfinger.ts
new file mode 100644
index 000000000..cf8eddfc7
--- /dev/null
+++ b/server/lib/activitypub/actors/webfinger.ts
@@ -0,0 +1,67 @@
1import * as WebFinger from 'webfinger.js'
2import { isTestInstance } from '@server/helpers/core-utils'
3import { isActivityPubUrlValid } from '@server/helpers/custom-validators/activitypub/misc'
4import { WEBSERVER } from '@server/initializers/constants'
5import { ActorModel } from '@server/models/actor/actor'
6import { MActorFull } from '@server/types/models'
7import { WebFingerData } from '@shared/models'
8
9const webfinger = new WebFinger({
10 webfist_fallback: false,
11 tls_only: isTestInstance(),
12 uri_fallback: false,
13 request_timeout: 3000
14})
15
16async function loadActorUrlOrGetFromWebfinger (uriArg: string) {
17 // Handle strings like @toto@example.com
18 const uri = uriArg.startsWith('@') ? uriArg.slice(1) : uriArg
19
20 const [ name, host ] = uri.split('@')
21 let actor: MActorFull
22
23 if (!host || host === WEBSERVER.HOST) {
24 actor = await ActorModel.loadLocalByName(name)
25 } else {
26 actor = await ActorModel.loadByNameAndHost(name, host)
27 }
28
29 if (actor) return actor.url
30
31 return getUrlFromWebfinger(uri)
32}
33
34async function getUrlFromWebfinger (uri: string) {
35 const webfingerData: WebFingerData = await webfingerLookup(uri)
36 return getLinkOrThrow(webfingerData)
37}
38
39// ---------------------------------------------------------------------------
40
41export {
42 getUrlFromWebfinger,
43 loadActorUrlOrGetFromWebfinger
44}
45
46// ---------------------------------------------------------------------------
47
48function getLinkOrThrow (webfingerData: WebFingerData) {
49 if (Array.isArray(webfingerData.links) === false) throw new Error('WebFinger links is not an array.')
50
51 const selfLink = webfingerData.links.find(l => l.rel === 'self')
52 if (selfLink === undefined || isActivityPubUrlValid(selfLink.href) === false) {
53 throw new Error('Cannot find self link or href is not a valid URL.')
54 }
55
56 return selfLink.href
57}
58
59function webfingerLookup (nameWithHost: string) {
60 return new Promise<WebFingerData>((res, rej) => {
61 webfinger.lookup(nameWithHost, (err, p) => {
62 if (err) return rej(err)
63
64 return res(p.object)
65 })
66 })
67}
diff --git a/server/lib/activitypub/videos/get.ts b/server/lib/activitypub/videos/get.ts
index a8c41e178..38ba4978c 100644
--- a/server/lib/activitypub/videos/get.ts
+++ b/server/lib/activitypub/videos/get.ts
@@ -1,7 +1,7 @@
1import { getAPId } from '@server/helpers/activitypub' 1import { getAPId } from '@server/helpers/activitypub'
2import { retryTransactionWrapper } from '@server/helpers/database-utils' 2import { retryTransactionWrapper } from '@server/helpers/database-utils'
3import { fetchVideoByUrl, VideoFetchByUrlType } from '@server/helpers/video'
4import { JobQueue } from '@server/lib/job-queue' 3import { JobQueue } from '@server/lib/job-queue'
4import { fetchVideoByUrl, VideoFetchByUrlType } from '@server/lib/model-loaders'
5import { MVideoAccountLightBlacklistAllFiles, MVideoImmutable, MVideoThumbnail } from '@server/types/models' 5import { MVideoAccountLightBlacklistAllFiles, MVideoImmutable, MVideoThumbnail } from '@server/types/models'
6import { refreshVideoIfNeeded } from './refresh' 6import { refreshVideoIfNeeded } from './refresh'
7import { APVideoCreator, fetchRemoteVideo, SyncParam, syncVideoExternalAttributes } from './shared' 7import { APVideoCreator, fetchRemoteVideo, SyncParam, syncVideoExternalAttributes } from './shared'
diff --git a/server/lib/activitypub/videos/refresh.ts b/server/lib/activitypub/videos/refresh.ts
index 71a4e75b0..f1a3a6fac 100644
--- a/server/lib/activitypub/videos/refresh.ts
+++ b/server/lib/activitypub/videos/refresh.ts
@@ -1,7 +1,7 @@
1import { logger, loggerTagsFactory } from '@server/helpers/logger' 1import { logger, loggerTagsFactory } from '@server/helpers/logger'
2import { PeerTubeRequestError } from '@server/helpers/requests' 2import { PeerTubeRequestError } from '@server/helpers/requests'
3import { VideoFetchByUrlType } from '@server/helpers/video'
4import { ActorFollowScoreCache } from '@server/lib/files-cache' 3import { ActorFollowScoreCache } from '@server/lib/files-cache'
4import { VideoFetchByUrlType } from '@server/lib/model-loaders'
5import { VideoModel } from '@server/models/video/video' 5import { VideoModel } from '@server/models/video/video'
6import { MVideoAccountLightBlacklistAllFiles, MVideoThumbnail } from '@server/types/models' 6import { MVideoAccountLightBlacklistAllFiles, MVideoThumbnail } from '@server/types/models'
7import { HttpStatusCode } from '@shared/core-utils' 7import { HttpStatusCode } from '@shared/core-utils'
diff --git a/server/lib/job-queue/handlers/activitypub-follow.ts b/server/lib/job-queue/handlers/activitypub-follow.ts
index 76b6fcaae..f896d7af4 100644
--- a/server/lib/job-queue/handlers/activitypub-follow.ts
+++ b/server/lib/job-queue/handlers/activitypub-follow.ts
@@ -4,13 +4,12 @@ import { ActivitypubFollowPayload } from '@shared/models'
4import { sanitizeHost } from '../../../helpers/core-utils' 4import { sanitizeHost } from '../../../helpers/core-utils'
5import { retryTransactionWrapper } from '../../../helpers/database-utils' 5import { retryTransactionWrapper } from '../../../helpers/database-utils'
6import { logger } from '../../../helpers/logger' 6import { logger } from '../../../helpers/logger'
7import { loadActorUrlOrGetFromWebfinger } from '../../../helpers/webfinger'
8import { REMOTE_SCHEME, WEBSERVER } from '../../../initializers/constants' 7import { REMOTE_SCHEME, WEBSERVER } from '../../../initializers/constants'
9import { sequelizeTypescript } from '../../../initializers/database' 8import { sequelizeTypescript } from '../../../initializers/database'
10import { ActorModel } from '../../../models/actor/actor' 9import { ActorModel } from '../../../models/actor/actor'
11import { ActorFollowModel } from '../../../models/actor/actor-follow' 10import { ActorFollowModel } from '../../../models/actor/actor-follow'
12import { MActor, MActorFollowActors, MActorFull } from '../../../types/models' 11import { MActor, MActorFollowActors, MActorFull } from '../../../types/models'
13import { getOrCreateAPActor } from '../../activitypub/actors' 12import { getOrCreateAPActor, loadActorUrlOrGetFromWebfinger } from '../../activitypub/actors'
14import { sendFollow } from '../../activitypub/send' 13import { sendFollow } from '../../activitypub/send'
15import { Notifier } from '../../notifier' 14import { Notifier } from '../../notifier'
16 15
diff --git a/server/lib/job-queue/handlers/activitypub-refresher.ts b/server/lib/job-queue/handlers/activitypub-refresher.ts
index 29483f310..2508a4793 100644
--- a/server/lib/job-queue/handlers/activitypub-refresher.ts
+++ b/server/lib/job-queue/handlers/activitypub-refresher.ts
@@ -1,9 +1,9 @@
1import * as Bull from 'bull' 1import * as Bull from 'bull'
2import { refreshVideoPlaylistIfNeeded } from '@server/lib/activitypub/playlists' 2import { refreshVideoPlaylistIfNeeded } from '@server/lib/activitypub/playlists'
3import { refreshVideoIfNeeded } from '@server/lib/activitypub/videos' 3import { refreshVideoIfNeeded } from '@server/lib/activitypub/videos'
4import { fetchVideoByUrl } from '@server/lib/model-loaders'
4import { RefreshPayload } from '@shared/models' 5import { RefreshPayload } from '@shared/models'
5import { logger } from '../../../helpers/logger' 6import { logger } from '../../../helpers/logger'
6import { fetchVideoByUrl } from '../../../helpers/video'
7import { ActorModel } from '../../../models/actor/actor' 7import { ActorModel } from '../../../models/actor/actor'
8import { VideoPlaylistModel } from '../../../models/video/video-playlist' 8import { VideoPlaylistModel } from '../../../models/video/video-playlist'
9import { refreshActorIfNeeded } from '../../activitypub/actors' 9import { refreshActorIfNeeded } from '../../activitypub/actors'
diff --git a/server/lib/model-loaders/actor.ts b/server/lib/model-loaders/actor.ts
new file mode 100644
index 000000000..234cb344f
--- /dev/null
+++ b/server/lib/model-loaders/actor.ts
@@ -0,0 +1,16 @@
1
2import { ActorModel } from '../../models/actor/actor'
3import { MActorAccountChannelId, MActorFull } from '../../types/models'
4
5type ActorFetchByUrlType = 'all' | 'association-ids'
6
7function fetchActorByUrl (url: string, fetchType: ActorFetchByUrlType): Promise<MActorFull | MActorAccountChannelId> {
8 if (fetchType === 'all') return ActorModel.loadByUrlAndPopulateAccountAndChannel(url)
9
10 if (fetchType === 'association-ids') return ActorModel.loadByUrl(url)
11}
12
13export {
14 ActorFetchByUrlType,
15 fetchActorByUrl
16}
diff --git a/server/lib/model-loaders/index.ts b/server/lib/model-loaders/index.ts
new file mode 100644
index 000000000..9e5152cb2
--- /dev/null
+++ b/server/lib/model-loaders/index.ts
@@ -0,0 +1,2 @@
1export * from './actor'
2export * from './video'
diff --git a/server/lib/model-loaders/video.ts b/server/lib/model-loaders/video.ts
new file mode 100644
index 000000000..7aaf00e89
--- /dev/null
+++ b/server/lib/model-loaders/video.ts
@@ -0,0 +1,64 @@
1import { VideoModel } from '@server/models/video/video'
2import {
3 MVideoAccountLightBlacklistAllFiles,
4 MVideoFullLight,
5 MVideoIdThumbnail,
6 MVideoImmutable,
7 MVideoThumbnail,
8 MVideoWithRights
9} from '@server/types/models'
10
11type VideoFetchType = 'all' | 'only-video' | 'only-video-with-rights' | 'id' | 'none' | 'only-immutable-attributes'
12
13function fetchVideo (id: number | string, fetchType: 'all', userId?: number): Promise<MVideoFullLight>
14function fetchVideo (id: number | string, fetchType: 'only-immutable-attributes'): Promise<MVideoImmutable>
15function fetchVideo (id: number | string, fetchType: 'only-video', userId?: number): Promise<MVideoThumbnail>
16function fetchVideo (id: number | string, fetchType: 'only-video-with-rights', userId?: number): Promise<MVideoWithRights>
17function fetchVideo (id: number | string, fetchType: 'id' | 'none', userId?: number): Promise<MVideoIdThumbnail>
18function fetchVideo (
19 id: number | string,
20 fetchType: VideoFetchType,
21 userId?: number
22): Promise<MVideoFullLight | MVideoThumbnail | MVideoWithRights | MVideoIdThumbnail | MVideoImmutable>
23function fetchVideo (
24 id: number | string,
25 fetchType: VideoFetchType,
26 userId?: number
27): Promise<MVideoFullLight | MVideoThumbnail | MVideoWithRights | MVideoIdThumbnail | MVideoImmutable> {
28 if (fetchType === 'all') return VideoModel.loadAndPopulateAccountAndServerAndTags(id, undefined, userId)
29
30 if (fetchType === 'only-immutable-attributes') return VideoModel.loadImmutableAttributes(id)
31
32 if (fetchType === 'only-video-with-rights') return VideoModel.loadWithRights(id)
33
34 if (fetchType === 'only-video') return VideoModel.load(id)
35
36 if (fetchType === 'id' || fetchType === 'none') return VideoModel.loadOnlyId(id)
37}
38
39type VideoFetchByUrlType = 'all' | 'only-video' | 'only-immutable-attributes'
40
41function fetchVideoByUrl (url: string, fetchType: 'all'): Promise<MVideoAccountLightBlacklistAllFiles>
42function fetchVideoByUrl (url: string, fetchType: 'only-immutable-attributes'): Promise<MVideoImmutable>
43function fetchVideoByUrl (url: string, fetchType: 'only-video'): Promise<MVideoThumbnail>
44function fetchVideoByUrl (
45 url: string,
46 fetchType: VideoFetchByUrlType
47): Promise<MVideoAccountLightBlacklistAllFiles | MVideoThumbnail | MVideoImmutable>
48function fetchVideoByUrl (
49 url: string,
50 fetchType: VideoFetchByUrlType
51): Promise<MVideoAccountLightBlacklistAllFiles | MVideoThumbnail | MVideoImmutable> {
52 if (fetchType === 'all') return VideoModel.loadByUrlAndPopulateAccount(url)
53
54 if (fetchType === 'only-immutable-attributes') return VideoModel.loadByUrlImmutableAttributes(url)
55
56 if (fetchType === 'only-video') return VideoModel.loadByUrl(url)
57}
58
59export {
60 VideoFetchType,
61 VideoFetchByUrlType,
62 fetchVideo,
63 fetchVideoByUrl
64}
diff --git a/server/lib/server-config-manager.ts b/server/lib/server-config-manager.ts
index 25a770c6b..80d87a9d3 100644
--- a/server/lib/server-config-manager.ts
+++ b/server/lib/server-config-manager.ts
@@ -1,7 +1,7 @@
1import { isSignupAllowed, isSignupAllowedForCurrentIP } from '@server/helpers/signup'
2import { getServerCommit } from '@server/helpers/utils' 1import { getServerCommit } from '@server/helpers/utils'
3import { CONFIG, isEmailEnabled } from '@server/initializers/config' 2import { CONFIG, isEmailEnabled } from '@server/initializers/config'
4import { CONSTRAINTS_FIELDS, DEFAULT_THEME_NAME, PEERTUBE_VERSION } from '@server/initializers/constants' 3import { CONSTRAINTS_FIELDS, DEFAULT_THEME_NAME, PEERTUBE_VERSION } from '@server/initializers/constants'
4import { isSignupAllowed, isSignupAllowedForCurrentIP } from '@server/lib/signup'
5import { ActorCustomPageModel } from '@server/models/account/actor-custom-page' 5import { ActorCustomPageModel } from '@server/models/account/actor-custom-page'
6import { HTMLServerConfig, RegisteredExternalAuthConfig, RegisteredIdAndPassAuthConfig, ServerConfig } from '@shared/models' 6import { HTMLServerConfig, RegisteredExternalAuthConfig, RegisteredIdAndPassAuthConfig, ServerConfig } from '@shared/models'
7import { Hooks } from './plugins/hooks' 7import { Hooks } from './plugins/hooks'
diff --git a/server/lib/signup.ts b/server/lib/signup.ts
new file mode 100644
index 000000000..8fa81e601
--- /dev/null
+++ b/server/lib/signup.ts
@@ -0,0 +1,62 @@
1import { UserModel } from '../models/user/user'
2import * as ipaddr from 'ipaddr.js'
3import { CONFIG } from '../initializers/config'
4
5const isCidr = require('is-cidr')
6
7async function isSignupAllowed (): Promise<{ allowed: boolean, errorMessage?: string }> {
8 if (CONFIG.SIGNUP.ENABLED === false) {
9 return { allowed: false }
10 }
11
12 // No limit and signup is enabled
13 if (CONFIG.SIGNUP.LIMIT === -1) {
14 return { allowed: true }
15 }
16
17 const totalUsers = await UserModel.countTotal()
18
19 return { allowed: totalUsers < CONFIG.SIGNUP.LIMIT }
20}
21
22function isSignupAllowedForCurrentIP (ip: string) {
23 if (!ip) return false
24
25 const addr = ipaddr.parse(ip)
26 const excludeList = [ 'blacklist' ]
27 let matched = ''
28
29 // if there is a valid, non-empty whitelist, we exclude all unknown adresses too
30 if (CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr(cidr)).length > 0) {
31 excludeList.push('unknown')
32 }
33
34 if (addr.kind() === 'ipv4') {
35 const addrV4 = ipaddr.IPv4.parse(ip)
36 const rangeList = {
37 whitelist: CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr.v4(cidr))
38 .map(cidr => ipaddr.IPv4.parseCIDR(cidr)),
39 blacklist: CONFIG.SIGNUP.FILTERS.CIDR.BLACKLIST.filter(cidr => isCidr.v4(cidr))
40 .map(cidr => ipaddr.IPv4.parseCIDR(cidr))
41 }
42 matched = ipaddr.subnetMatch(addrV4, rangeList, 'unknown')
43 } else if (addr.kind() === 'ipv6') {
44 const addrV6 = ipaddr.IPv6.parse(ip)
45 const rangeList = {
46 whitelist: CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr.v6(cidr))
47 .map(cidr => ipaddr.IPv6.parseCIDR(cidr)),
48 blacklist: CONFIG.SIGNUP.FILTERS.CIDR.BLACKLIST.filter(cidr => isCidr.v6(cidr))
49 .map(cidr => ipaddr.IPv6.parseCIDR(cidr))
50 }
51 matched = ipaddr.subnetMatch(addrV6, rangeList, 'unknown')
52 }
53
54 return !excludeList.includes(matched)
55}
56
57// ---------------------------------------------------------------------------
58
59export {
60 isSignupAllowed,
61 isSignupAllowedForCurrentIP
62}