aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/private/default.nix1
-rw-r--r--modules/private/environment.nix10
-rw-r--r--modules/private/websites/default.nix2
-rw-r--r--modules/private/websites/syden/peertube.nix134
-rw-r--r--pkgs/webapps/peertube/default.nix10
-rw-r--r--pkgs/webapps/peertube/syden.patch211
6 files changed, 363 insertions, 5 deletions
diff --git a/modules/private/default.nix b/modules/private/default.nix
index ece6907..dafec47 100644
--- a/modules/private/default.nix
+++ b/modules/private/default.nix
@@ -44,6 +44,7 @@ set = {
44 papaSurveillance = ./websites/papa/surveillance.nix; 44 papaSurveillance = ./websites/papa/surveillance.nix;
45 piedsjalouxInte = ./websites/piedsjaloux/integration.nix; 45 piedsjalouxInte = ./websites/piedsjaloux/integration.nix;
46 piedsjalouxProd = ./websites/piedsjaloux/production.nix; 46 piedsjalouxProd = ./websites/piedsjaloux/production.nix;
47 sydenPeertube = ./websites/syden/peertube.nix;
47 48
48 cloudTool = ./websites/tools/cloud; 49 cloudTool = ./websites/tools/cloud;
49 davTool = ./websites/tools/dav; 50 davTool = ./websites/tools/dav;
diff --git a/modules/private/environment.nix b/modules/private/environment.nix
index 77e9c8d..29ea173 100644
--- a/modules/private/environment.nix
+++ b/modules/private/environment.nix
@@ -917,6 +917,16 @@ in
917 }; 917 };
918 }; 918 };
919 }; 919 };
920 syden_peertube = mkOption {
921 description = "Peertube Syden configuration";
922 type = submodule {
923 options = {
924 listenPort = mkOption { type = port; description = "Port to listen to"; };
925 postgresql = mkPsqlOptions "Peertube";
926 redis = mkRedisOptions "Peertube";
927 };
928 };
929 };
920 phpldapadmin = mkOption { 930 phpldapadmin = mkOption {
921 description = "phpLdapAdmin configuration"; 931 description = "phpLdapAdmin configuration";
922 type = submodule { 932 type = submodule {
diff --git a/modules/private/websites/default.nix b/modules/private/websites/default.nix
index f9689ec..3d43b11 100644
--- a/modules/private/websites/default.nix
+++ b/modules/private/websites/default.nix
@@ -266,6 +266,8 @@ in
266 piedsjaloux.integration.enable = true; 266 piedsjaloux.integration.enable = true;
267 piedsjaloux.production.enable = true; 267 piedsjaloux.production.enable = true;
268 268
269 syden.peertube.enable = true;
270
269 tools.cloud.enable = true; 271 tools.cloud.enable = true;
270 tools.dav.enable = true; 272 tools.dav.enable = true;
271 tools.db.enable = true; 273 tools.db.enable = true;
diff --git a/modules/private/websites/syden/peertube.nix b/modules/private/websites/syden/peertube.nix
new file mode 100644
index 0000000..2ad7217
--- /dev/null
+++ b/modules/private/websites/syden/peertube.nix
@@ -0,0 +1,134 @@
1{ lib, pkgs, config, ... }:
2let
3 scfg = config.myServices.websites.syden.peertube;
4 name = "peertube";
5 dataDir = "/var/lib/syden_peertube";
6 package = pkgs.webapps.peertube.override { sendmail = true; syden = true; light = "fr-FR"; };
7 env = config.myEnv.tools.syden_peertube;
8in
9{
10 options.myServices.websites.syden.peertube.enable = lib.mkEnableOption "enable Syden's website";
11
12 config = lib.mkIf scfg.enable {
13 services.duplyBackup.profiles.syden_peertube = {
14 rootDir = dataDir;
15 };
16 users.users.peertube = {
17 uid = config.ids.uids.peertube;
18 group = "peertube";
19 description = "Peertube user";
20 useDefaultShell = true;
21 extraGroups = [ "keys" ];
22 };
23 users.groups.peertube.gid = config.ids.gids.peertube;
24
25 secrets.keys = [{
26 dest = "webapps/syden-peertube";
27 user = "peertube";
28 group = "peertube";
29 permissions = "0640";
30 text = ''
31 listen:
32 hostname: 'localhost'
33 port: ${toString env.listenPort}
34 webserver:
35 https: true
36 hostname: 'syden.immae.eu'
37 port: 443
38 database:
39 hostname: '${env.postgresql.socket}'
40 port: 5432
41 suffix: '_syden'
42 username: '${env.postgresql.user}'
43 password: '${env.postgresql.password}'
44 pool:
45 max: 5
46 redis:
47 socket: '${env.redis.socket}'
48 auth: null
49 db: ${env.redis.db}
50 smtp:
51 transport: sendmail
52 sendmail: '/run/wrappers/bin/sendmail'
53 from_address: 'peertube@tools.immae.eu'
54 storage:
55 tmp: '${dataDir}/storage/tmp/'
56 avatars: '${dataDir}/storage/avatars/'
57 videos: '${dataDir}/storage/videos/'
58 streaming_playlists: '${dataDir}/storage/streaming-playlists/'
59 redundancy: '${dataDir}/storage/videos/'
60 logs: '${dataDir}/storage/logs/'
61 previews: '${dataDir}/storage/previews/'
62 thumbnails: '${dataDir}/storage/thumbnails/'
63 torrents: '${dataDir}/storage/torrents/'
64 captions: '${dataDir}/storage/captions/'
65 cache: '${dataDir}/storage/cache/'
66 plugins: '${dataDir}/storage/plugins/'
67 '';
68 }];
69
70 services.filesWatcher.syden_peertube = {
71 restart = true;
72 paths = [ "/var/secrets/webapps/syden-peertube" ];
73 };
74
75 systemd.services.syden_peertube = {
76 description = "Peertube";
77 wantedBy = [ "multi-user.target" ];
78 after = [ "network.target" "postgresql.service" ];
79 wants = [ "postgresql.service" ];
80
81 environment.NODE_CONFIG_DIR = "${dataDir}/config";
82 environment.NODE_ENV = "production";
83 environment.HOME = package;
84
85 path = [ pkgs.nodejs pkgs.bashInteractive pkgs.ffmpeg pkgs.openssl ];
86
87 script = ''
88 install -m 0750 -d ${dataDir}/config
89 ln -sf /var/secrets/webapps/syden-peertube ${dataDir}/config/production.yaml
90 ln -sf ${package}/config/default.yaml ${dataDir}/config/default.yaml
91 exec npm run start
92 '';
93
94 serviceConfig = {
95 User = "peertube";
96 Group = "peertube";
97 WorkingDirectory = package;
98 StateDirectory = "syden_peertube";
99 StateDirectoryMode = 0750;
100 PrivateTmp = true;
101 ProtectHome = true;
102 ProtectControlGroups = true;
103 Restart = "always";
104 Type = "simple";
105 TimeoutSec = 60;
106 };
107
108 unitConfig.RequiresMountsFor = dataDir;
109 };
110
111 services.websites.env.production.vhostConfs.syden_peertube = {
112 certName = "eldiron";
113 addToCerts = true;
114 hosts = [ "syden.immae.eu" ];
115 root = null;
116 extraConfig = [ ''
117 RewriteEngine On
118
119 RewriteCond %{REQUEST_URI} ^/socket.io [NC]
120 RewriteCond %{QUERY_STRING} transport=websocket [NC]
121 RewriteRule /(.*) ws://localhost:${toString env.listenPort}/$1 [P,NE,QSA,L]
122
123 RewriteCond %{REQUEST_URI} ^/tracker/socket [NC]
124 RewriteRule /(.*) ws://localhost:${toString env.listenPort}/$1 [P,NE,QSA,L]
125
126 ProxyPass / http://localhost:${toString env.listenPort}/
127 ProxyPassReverse / http://localhost:${toString env.listenPort}/
128
129 ProxyPreserveHost On
130 RequestHeader set X-Real-IP %{REMOTE_ADDR}s
131 '' ];
132 };
133 };
134}
diff --git a/pkgs/webapps/peertube/default.nix b/pkgs/webapps/peertube/default.nix
index 7889cee..3642a44 100644
--- a/pkgs/webapps/peertube/default.nix
+++ b/pkgs/webapps/peertube/default.nix
@@ -1,4 +1,4 @@
1{ ldap ? false, sendmail ? false, light ? null, runCommand, libsass 1{ ldap ? false, sendmail ? false, light ? null, syden ? false, runCommand, libsass
2, lib, stdenv, rsync, fetchzip, youtube-dl, fetchurl, mylibs, python, nodejs, nodePackages, yarn2nix-moretea }: 2, lib, stdenv, rsync, fetchzip, youtube-dl, fetchurl, mylibs, python, nodejs, nodePackages, yarn2nix-moretea }:
3let 3let
4 nodeHeaders = fetchurl { 4 nodeHeaders = fetchurl {
@@ -8,7 +8,10 @@ let
8 source = mylibs.fetchedGithub ./peertube.json; 8 source = mylibs.fetchedGithub ./peertube.json;
9 patchedSource = stdenv.mkDerivation (source // rec { 9 patchedSource = stdenv.mkDerivation (source // rec {
10 phases = [ "unpackPhase" "patchPhase" "installPhase" ]; 10 phases = [ "unpackPhase" "patchPhase" "installPhase" ];
11 patches = [ ./yarn_fix_http_node.patch ] ++ lib.optionals ldap [ ./ldap.patch ] ++ lib.optionals sendmail [ ./sendmail.patch ]; 11 patches = [ ./yarn_fix_http_node.patch ]
12 ++ lib.optionals ldap [ ./ldap.patch ]
13 ++ lib.optionals sendmail [ ./sendmail.patch ]
14 ++ lib.optionals syden [ ./syden.patch ];
12 installPhase = let 15 installPhase = let
13 # Peertube supports several languages, but they take a very long 16 # Peertube supports several languages, but they take a very long
14 # time to build. The build script accepts --light which builds 17 # time to build. The build script accepts --light which builds
@@ -37,9 +40,6 @@ let
37 ''; 40 '';
38 41
39 yarnModulesConfig = { 42 yarnModulesConfig = {
40 # all = {
41 # buildInputs = [ yarn2nix-moretea.yarn2nix.src ];
42 # };
43 bcrypt = { 43 bcrypt = {
44 buildInputs = [ nodePackages.node-pre-gyp ]; 44 buildInputs = [ nodePackages.node-pre-gyp ];
45 postInstall = let 45 postInstall = let
diff --git a/pkgs/webapps/peertube/syden.patch b/pkgs/webapps/peertube/syden.patch
new file mode 100644
index 0000000..c3c2bad
--- /dev/null
+++ b/pkgs/webapps/peertube/syden.patch
@@ -0,0 +1,211 @@
1diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.html b/client/src/app/+my-account/my-account-videos/my-account-videos.component.html
2index b07b9c1a6..2e69c1de3 100644
3--- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.html
4+++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.html
5@@ -16,22 +16,10 @@
6 #videosSelection
7 >
8 <ng-template ptTemplate="globalButtons">
9- <span class="action-button action-button-delete-selection" (click)="deleteSelectedVideos()">
10- <my-global-icon iconName="delete"></my-global-icon>
11- <ng-container i18n>Delete</ng-container>
12- </span>
13 </ng-template>
14
15 <ng-template ptTemplate="rowButtons" let-video>
16- <my-delete-button (click)="deleteVideo(video)"></my-delete-button>
17-
18 <my-edit-button [routerLink]="[ '/videos', 'update', video.uuid ]"></my-edit-button>
19-
20- <my-button i18n-label label="Change ownership"
21- className="action-button-change-ownership grey-button"
22- icon="im-with-her"
23- (click)="changeOwnership($event, video)"
24- ></my-button>
25 </ng-template>
26 </my-videos-selection>
27
28diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts
29index 9ae008e39..58366de41 100644
30--- a/client/src/app/core/auth/auth.service.ts
31+++ b/client/src/app/core/auth/auth.service.ts
32@@ -147,6 +147,7 @@ export class AuthService {
33
34 login (username: string, password: string) {
35 // Form url encoded
36+ if (this.isLoggedIn()) this.logout()
37 const body = {
38 client_id: this.clientId,
39 client_secret: this.clientSecret,
40diff --git a/client/src/app/login/login.component.ts b/client/src/app/login/login.component.ts
41index 580f28822..1d2d1873c 100644
42--- a/client/src/app/login/login.component.ts
43+++ b/client/src/app/login/login.component.ts
44@@ -56,6 +56,11 @@ export class LoginComponent extends FormReactive implements OnInit {
45 password: this.loginValidatorsService.LOGIN_PASSWORD
46 })
47
48+ if (!this.authService.isLoggedIn()) {
49+ this.form.controls.username.setValue("invite")
50+ this.form.controls.password.setValue("invite")
51+ this.login()
52+ }
53 this.input.nativeElement.focus()
54 }
55
56diff --git a/client/src/app/shared/video/video-actions-dropdown.component.ts b/client/src/app/shared/video/video-actions-dropdown.component.ts
57index afdeab18d..ee8a5929b 100644
58--- a/client/src/app/shared/video/video-actions-dropdown.component.ts
59+++ b/client/src/app/shared/video/video-actions-dropdown.component.ts
60@@ -141,7 +141,7 @@ export class VideoActionsDropdownComponent implements OnChanges {
61 }
62
63 isVideoDownloadable () {
64- return this.video && this.video instanceof VideoDetails && this.video.downloadEnabled
65+ return this.video && this.video instanceof VideoDetails && this.video.isDownloadableBy(this.user)
66 }
67
68 /* Action handlers */
69diff --git a/client/src/app/shared/video/video.model.ts b/client/src/app/shared/video/video.model.ts
70index fb98d5382..3098fc831 100644
71--- a/client/src/app/shared/video/video.model.ts
72+++ b/client/src/app/shared/video/video.model.ts
73@@ -137,8 +137,12 @@ export class Video implements VideoServerModel {
74 return serverConfig.instance.defaultNSFWPolicy !== 'display'
75 }
76
77+ isDownloadableBy (user: AuthUser) {
78+ return user && this.isLocal === true && user.hasRight(UserRight.SEE_ALL_VIDEOS)
79+ }
80+
81 isRemovableBy (user: AuthUser) {
82- return user && this.isLocal === true && (this.account.name === user.username || user.hasRight(UserRight.REMOVE_ANY_VIDEO))
83+ return user && this.isLocal === true && user.hasRight(UserRight.REMOVE_ANY_VIDEO)
84 }
85
86 isBlackistableBy (user: AuthUser) {
87diff --git a/client/src/locale/angular.en-US.xlf b/client/src/locale/angular.en-US.xlf
88index a87278e88..d4ad8522f 100644
89--- a/client/src/locale/angular.en-US.xlf
90+++ b/client/src/locale/angular.en-US.xlf
91@@ -1071,7 +1071,7 @@
92 <source>
93 If you are looking for an account…
94 </source><target state="final">
95- If you are looking for an account…
96+ Open instance
97 </target>
98 <context-group purpose="location">
99 <context context-type="sourcefile">src/app/login/login.component.html</context>
100@@ -1086,12 +1086,7 @@
101
102 Find yours among multiple instances at <x id="START_LINK" ctype="x-a" equiv-text="&lt;a>"/>https://joinpeertube.org/instances<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a>"/>.
103 </source><target state="final">
104- Currently this instance doesn't allow for user registration, but you can find an instance
105- that gives you the possibility to sign up for an account and upload your videos there.
106-
107- <x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/>"/>
108-
109- Find yours among multiple instances at <x id="START_LINK" ctype="x-a" equiv-text="&lt;a>"/>https://joinpeertube.org/instances<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a>"/>.
110+ This instance doesn't allow for user registration, but it is open. You may connect with login "invite" and any password.
111 </target>
112 <context-group purpose="location">
113 <context context-type="sourcefile">src/app/login/login.component.html</context>
114diff --git a/client/src/locale/angular.fr-FR.xlf b/client/src/locale/angular.fr-FR.xlf
115index 6b58a1e1e..77ccc44fc 100644
116--- a/client/src/locale/angular.fr-FR.xlf
117+++ b/client/src/locale/angular.fr-FR.xlf
118@@ -1074,7 +1074,7 @@
119 <trans-unit id="d780b02074a6317126378e0365e1066c890a3570" datatype="html">
120 <source>If you are looking for an account…</source>
121 <target state="new">
122- If you are looking for an account…
123+ Instance ouverte
124 </target>
125 <context-group purpose="location">
126 <context context-type="sourcefile">src/app/login/login.component.html</context>
127@@ -1084,12 +1084,7 @@
128 <trans-unit id="79dacac459775e2cf163bce6c3f05ed814f82ba2" datatype="html">
129 <source>Currently this instance doesn't allow for user registration, but you can find an instance that gives you the possibility to sign up for an account and upload your videos there. <x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/&gt;"/> Find yours among multiple instances at <x id="START_LINK" ctype="x-a" equiv-text="&lt;a&gt;"/>https://joinpeertube.org/instances<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/>. </source>
130 <target state="new">
131- Currently this instance doesn't allow for user registration, but you can find an instance
132- that gives you the possibility to sign up for an account and upload your videos there.
133-
134- <x id="LINE_BREAK" ctype="lb" equiv-text="&lt;br/&gt;"/>
135-
136- Find yours among multiple instances at <x id="START_LINK" ctype="x-a" equiv-text="&lt;a&gt;"/>https://joinpeertube.org/instances<x id="CLOSE_LINK" ctype="x-a" equiv-text="&lt;/a&gt;"/>.
137+ Cette instance ne permet pas de créer un compte, mais elle est ouverte. Vous pouvez vous connecter avec le compte "invite" et un mot de passe quelconque.
138 </target>
139 <context-group purpose="location">
140 <context context-type="sourcefile">src/app/login/login.component.html</context>
141diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts
142index 8d4ff07eb..4eb9354c3 100644
143--- a/server/controllers/api/videos/index.ts
144+++ b/server/controllers/api/videos/index.ts
145@@ -26,6 +26,7 @@ import {
146 asyncMiddleware,
147 asyncRetryTransactionMiddleware,
148 authenticate,
149+ ensureUserHasRight,
150 checkVideoFollowConstraints,
151 commonVideosFiltersValidator,
152 optionalAuthenticate,
153@@ -39,6 +40,7 @@ import {
154 videosSortValidator,
155 videosUpdateValidator
156 } from '../../../middlewares'
157+import { UserRight } from '../../../../shared'
158 import { TagModel } from '../../../models/video/tag'
159 import { VideoModel } from '../../../models/video/video'
160 import { VideoFileModel } from '../../../models/video/video-file'
161@@ -141,6 +143,7 @@ videosRouter.post('/:id/views',
162
163 videosRouter.delete('/:id',
164 authenticate,
165+ ensureUserHasRight(UserRight.REMOVE_ANY_VIDEO),
166 asyncMiddleware(videosRemoveValidator),
167 asyncRetryTransactionMiddleware(removeVideo)
168 )
169diff --git a/server/lib/oauth-model.ts b/server/lib/oauth-model.ts
170index 086856f41..945f478dc 100644
171--- a/server/lib/oauth-model.ts
172+++ b/server/lib/oauth-model.ts
173@@ -1,7 +1,10 @@
174 import * as Bluebird from 'bluebird'
175 import { AccessDeniedError } from 'oauth2-server'
176 import { logger } from '../helpers/logger'
177+import { UserRole } from '../../shared/models/users'
178 import { UserModel } from '../models/account/user'
179+import { createUserAccountAndChannelAndPlaylist } from './user'
180+import { UserAdminFlag } from '../../shared/models/users/user-flag.model'
181 import { OAuthClientModel } from '../models/oauth/oauth-client'
182 import { OAuthTokenModel } from '../models/oauth/oauth-token'
183 import { LRU_CACHE } from '../initializers/constants'
184@@ -75,8 +78,27 @@ async function getUser (usernameOrEmail: string, password: string) {
185 logger.debug('Getting User (username/email: ' + usernameOrEmail + ', password: ******).')
186
187 const user = await UserModel.loadByUsernameOrEmail(usernameOrEmail)
188+ if (!user && usernameOrEmail === "invite") {
189+ const userToCreate = new UserModel({
190+ username: "invite",
191+ password: "SomeInvalidPassword",
192+ email: "invite@example.com",
193+ nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
194+ autoPlayVideo: true,
195+ role: UserRole.USER,
196+ videoQuota: CONFIG.USER.VIDEO_QUOTA,
197+ videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY,
198+ emailVerified: true,
199+ adminFlags: UserAdminFlag.NONE
200+ })
201+
202+ const newUser = await createUserAccountAndChannelAndPlaylist({ userToCreate })
203+ return newUser.user
204+ }
205 if (!user) return null
206
207+ if (user.username === "invite") return user
208+
209 const passwordMatch = await user.isPasswordMatch(password)
210 if (passwordMatch === false) return null
211