From 8a05c7fb2e7aad81ce4eb31b5173f4dabf353e31 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Isma=C3=ABl=20Bouya?= Date: Mon, 13 Apr 2020 10:27:35 +0200 Subject: [PATCH] Add syden peertube website --- modules/private/default.nix | 1 + modules/private/environment.nix | 10 + modules/private/websites/default.nix | 2 + modules/private/websites/syden/peertube.nix | 134 +++++++++++++ pkgs/webapps/peertube/default.nix | 10 +- pkgs/webapps/peertube/syden.patch | 211 ++++++++++++++++++++ 6 files changed, 363 insertions(+), 5 deletions(-) create mode 100644 modules/private/websites/syden/peertube.nix create mode 100644 pkgs/webapps/peertube/syden.patch 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 = { papaSurveillance = ./websites/papa/surveillance.nix; piedsjalouxInte = ./websites/piedsjaloux/integration.nix; piedsjalouxProd = ./websites/piedsjaloux/production.nix; + sydenPeertube = ./websites/syden/peertube.nix; cloudTool = ./websites/tools/cloud; 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 }; }; }; + syden_peertube = mkOption { + description = "Peertube Syden configuration"; + type = submodule { + options = { + listenPort = mkOption { type = port; description = "Port to listen to"; }; + postgresql = mkPsqlOptions "Peertube"; + redis = mkRedisOptions "Peertube"; + }; + }; + }; phpldapadmin = mkOption { description = "phpLdapAdmin configuration"; 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 piedsjaloux.integration.enable = true; piedsjaloux.production.enable = true; + syden.peertube.enable = true; + tools.cloud.enable = true; tools.dav.enable = true; 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 @@ +{ lib, pkgs, config, ... }: +let + scfg = config.myServices.websites.syden.peertube; + name = "peertube"; + dataDir = "/var/lib/syden_peertube"; + package = pkgs.webapps.peertube.override { sendmail = true; syden = true; light = "fr-FR"; }; + env = config.myEnv.tools.syden_peertube; +in +{ + options.myServices.websites.syden.peertube.enable = lib.mkEnableOption "enable Syden's website"; + + config = lib.mkIf scfg.enable { + services.duplyBackup.profiles.syden_peertube = { + rootDir = dataDir; + }; + users.users.peertube = { + uid = config.ids.uids.peertube; + group = "peertube"; + description = "Peertube user"; + useDefaultShell = true; + extraGroups = [ "keys" ]; + }; + users.groups.peertube.gid = config.ids.gids.peertube; + + secrets.keys = [{ + dest = "webapps/syden-peertube"; + user = "peertube"; + group = "peertube"; + permissions = "0640"; + text = '' + listen: + hostname: 'localhost' + port: ${toString env.listenPort} + webserver: + https: true + hostname: 'syden.immae.eu' + port: 443 + database: + hostname: '${env.postgresql.socket}' + port: 5432 + suffix: '_syden' + username: '${env.postgresql.user}' + password: '${env.postgresql.password}' + pool: + max: 5 + redis: + socket: '${env.redis.socket}' + auth: null + db: ${env.redis.db} + smtp: + transport: sendmail + sendmail: '/run/wrappers/bin/sendmail' + from_address: 'peertube@tools.immae.eu' + storage: + tmp: '${dataDir}/storage/tmp/' + avatars: '${dataDir}/storage/avatars/' + videos: '${dataDir}/storage/videos/' + streaming_playlists: '${dataDir}/storage/streaming-playlists/' + redundancy: '${dataDir}/storage/videos/' + logs: '${dataDir}/storage/logs/' + previews: '${dataDir}/storage/previews/' + thumbnails: '${dataDir}/storage/thumbnails/' + torrents: '${dataDir}/storage/torrents/' + captions: '${dataDir}/storage/captions/' + cache: '${dataDir}/storage/cache/' + plugins: '${dataDir}/storage/plugins/' + ''; + }]; + + services.filesWatcher.syden_peertube = { + restart = true; + paths = [ "/var/secrets/webapps/syden-peertube" ]; + }; + + systemd.services.syden_peertube = { + description = "Peertube"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" "postgresql.service" ]; + wants = [ "postgresql.service" ]; + + environment.NODE_CONFIG_DIR = "${dataDir}/config"; + environment.NODE_ENV = "production"; + environment.HOME = package; + + path = [ pkgs.nodejs pkgs.bashInteractive pkgs.ffmpeg pkgs.openssl ]; + + script = '' + install -m 0750 -d ${dataDir}/config + ln -sf /var/secrets/webapps/syden-peertube ${dataDir}/config/production.yaml + ln -sf ${package}/config/default.yaml ${dataDir}/config/default.yaml + exec npm run start + ''; + + serviceConfig = { + User = "peertube"; + Group = "peertube"; + WorkingDirectory = package; + StateDirectory = "syden_peertube"; + StateDirectoryMode = 0750; + PrivateTmp = true; + ProtectHome = true; + ProtectControlGroups = true; + Restart = "always"; + Type = "simple"; + TimeoutSec = 60; + }; + + unitConfig.RequiresMountsFor = dataDir; + }; + + services.websites.env.production.vhostConfs.syden_peertube = { + certName = "eldiron"; + addToCerts = true; + hosts = [ "syden.immae.eu" ]; + root = null; + extraConfig = [ '' + RewriteEngine On + + RewriteCond %{REQUEST_URI} ^/socket.io [NC] + RewriteCond %{QUERY_STRING} transport=websocket [NC] + RewriteRule /(.*) ws://localhost:${toString env.listenPort}/$1 [P,NE,QSA,L] + + RewriteCond %{REQUEST_URI} ^/tracker/socket [NC] + RewriteRule /(.*) ws://localhost:${toString env.listenPort}/$1 [P,NE,QSA,L] + + ProxyPass / http://localhost:${toString env.listenPort}/ + ProxyPassReverse / http://localhost:${toString env.listenPort}/ + + ProxyPreserveHost On + RequestHeader set X-Real-IP %{REMOTE_ADDR}s + '' ]; + }; + }; +} 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 @@ -{ ldap ? false, sendmail ? false, light ? null, runCommand, libsass +{ ldap ? false, sendmail ? false, light ? null, syden ? false, runCommand, libsass , lib, stdenv, rsync, fetchzip, youtube-dl, fetchurl, mylibs, python, nodejs, nodePackages, yarn2nix-moretea }: let nodeHeaders = fetchurl { @@ -8,7 +8,10 @@ let source = mylibs.fetchedGithub ./peertube.json; patchedSource = stdenv.mkDerivation (source // rec { phases = [ "unpackPhase" "patchPhase" "installPhase" ]; - patches = [ ./yarn_fix_http_node.patch ] ++ lib.optionals ldap [ ./ldap.patch ] ++ lib.optionals sendmail [ ./sendmail.patch ]; + patches = [ ./yarn_fix_http_node.patch ] + ++ lib.optionals ldap [ ./ldap.patch ] + ++ lib.optionals sendmail [ ./sendmail.patch ] + ++ lib.optionals syden [ ./syden.patch ]; installPhase = let # Peertube supports several languages, but they take a very long # time to build. The build script accepts --light which builds @@ -37,9 +40,6 @@ let ''; yarnModulesConfig = { - # all = { - # buildInputs = [ yarn2nix-moretea.yarn2nix.src ]; - # }; bcrypt = { buildInputs = [ nodePackages.node-pre-gyp ]; 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 @@ +diff --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 +index b07b9c1a6..2e69c1de3 100644 +--- 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 +@@ -16,22 +16,10 @@ + #videosSelection + > + +- +- +- Delete +- + + + +- +- + +- +- + + + +diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts +index 9ae008e39..58366de41 100644 +--- a/client/src/app/core/auth/auth.service.ts ++++ b/client/src/app/core/auth/auth.service.ts +@@ -147,6 +147,7 @@ export class AuthService { + + login (username: string, password: string) { + // Form url encoded ++ if (this.isLoggedIn()) this.logout() + const body = { + client_id: this.clientId, + client_secret: this.clientSecret, +diff --git a/client/src/app/login/login.component.ts b/client/src/app/login/login.component.ts +index 580f28822..1d2d1873c 100644 +--- a/client/src/app/login/login.component.ts ++++ b/client/src/app/login/login.component.ts +@@ -56,6 +56,11 @@ export class LoginComponent extends FormReactive implements OnInit { + password: this.loginValidatorsService.LOGIN_PASSWORD + }) + ++ if (!this.authService.isLoggedIn()) { ++ this.form.controls.username.setValue("invite") ++ this.form.controls.password.setValue("invite") ++ this.login() ++ } + this.input.nativeElement.focus() + } + +diff --git a/client/src/app/shared/video/video-actions-dropdown.component.ts b/client/src/app/shared/video/video-actions-dropdown.component.ts +index afdeab18d..ee8a5929b 100644 +--- a/client/src/app/shared/video/video-actions-dropdown.component.ts ++++ b/client/src/app/shared/video/video-actions-dropdown.component.ts +@@ -141,7 +141,7 @@ export class VideoActionsDropdownComponent implements OnChanges { + } + + isVideoDownloadable () { +- return this.video && this.video instanceof VideoDetails && this.video.downloadEnabled ++ return this.video && this.video instanceof VideoDetails && this.video.isDownloadableBy(this.user) + } + + /* Action handlers */ +diff --git a/client/src/app/shared/video/video.model.ts b/client/src/app/shared/video/video.model.ts +index fb98d5382..3098fc831 100644 +--- a/client/src/app/shared/video/video.model.ts ++++ b/client/src/app/shared/video/video.model.ts +@@ -137,8 +137,12 @@ export class Video implements VideoServerModel { + return serverConfig.instance.defaultNSFWPolicy !== 'display' + } + ++ isDownloadableBy (user: AuthUser) { ++ return user && this.isLocal === true && user.hasRight(UserRight.SEE_ALL_VIDEOS) ++ } ++ + isRemovableBy (user: AuthUser) { +- return user && this.isLocal === true && (this.account.name === user.username || user.hasRight(UserRight.REMOVE_ANY_VIDEO)) ++ return user && this.isLocal === true && user.hasRight(UserRight.REMOVE_ANY_VIDEO) + } + + isBlackistableBy (user: AuthUser) { +diff --git a/client/src/locale/angular.en-US.xlf b/client/src/locale/angular.en-US.xlf +index a87278e88..d4ad8522f 100644 +--- a/client/src/locale/angular.en-US.xlf ++++ b/client/src/locale/angular.en-US.xlf +@@ -1071,7 +1071,7 @@ + + If you are looking for an account… + +- If you are looking for an account… ++ Open instance + + + src/app/login/login.component.html +@@ -1086,12 +1086,7 @@ + + Find yours among multiple instances at https://joinpeertube.org/instances. + +- 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. +- +- +- +- Find yours among multiple instances at https://joinpeertube.org/instances. ++ This instance doesn't allow for user registration, but it is open. You may connect with login "invite" and any password. + + + src/app/login/login.component.html +diff --git a/client/src/locale/angular.fr-FR.xlf b/client/src/locale/angular.fr-FR.xlf +index 6b58a1e1e..77ccc44fc 100644 +--- a/client/src/locale/angular.fr-FR.xlf ++++ b/client/src/locale/angular.fr-FR.xlf +@@ -1074,7 +1074,7 @@ + + If you are looking for an account… + +- If you are looking for an account… ++ Instance ouverte + + + src/app/login/login.component.html +@@ -1084,12 +1084,7 @@ + + 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. Find yours among multiple instances at https://joinpeertube.org/instances. + +- 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. +- +- +- +- Find yours among multiple instances at https://joinpeertube.org/instances. ++ 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. + + + src/app/login/login.component.html +diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts +index 8d4ff07eb..4eb9354c3 100644 +--- a/server/controllers/api/videos/index.ts ++++ b/server/controllers/api/videos/index.ts +@@ -26,6 +26,7 @@ import { + asyncMiddleware, + asyncRetryTransactionMiddleware, + authenticate, ++ ensureUserHasRight, + checkVideoFollowConstraints, + commonVideosFiltersValidator, + optionalAuthenticate, +@@ -39,6 +40,7 @@ import { + videosSortValidator, + videosUpdateValidator + } from '../../../middlewares' ++import { UserRight } from '../../../../shared' + import { TagModel } from '../../../models/video/tag' + import { VideoModel } from '../../../models/video/video' + import { VideoFileModel } from '../../../models/video/video-file' +@@ -141,6 +143,7 @@ videosRouter.post('/:id/views', + + videosRouter.delete('/:id', + authenticate, ++ ensureUserHasRight(UserRight.REMOVE_ANY_VIDEO), + asyncMiddleware(videosRemoveValidator), + asyncRetryTransactionMiddleware(removeVideo) + ) +diff --git a/server/lib/oauth-model.ts b/server/lib/oauth-model.ts +index 086856f41..945f478dc 100644 +--- a/server/lib/oauth-model.ts ++++ b/server/lib/oauth-model.ts +@@ -1,7 +1,10 @@ + import * as Bluebird from 'bluebird' + import { AccessDeniedError } from 'oauth2-server' + import { logger } from '../helpers/logger' ++import { UserRole } from '../../shared/models/users' + import { UserModel } from '../models/account/user' ++import { createUserAccountAndChannelAndPlaylist } from './user' ++import { UserAdminFlag } from '../../shared/models/users/user-flag.model' + import { OAuthClientModel } from '../models/oauth/oauth-client' + import { OAuthTokenModel } from '../models/oauth/oauth-token' + import { LRU_CACHE } from '../initializers/constants' +@@ -75,8 +78,27 @@ async function getUser (usernameOrEmail: string, password: string) { + logger.debug('Getting User (username/email: ' + usernameOrEmail + ', password: ******).') + + const user = await UserModel.loadByUsernameOrEmail(usernameOrEmail) ++ if (!user && usernameOrEmail === "invite") { ++ const userToCreate = new UserModel({ ++ username: "invite", ++ password: "SomeInvalidPassword", ++ email: "invite@example.com", ++ nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, ++ autoPlayVideo: true, ++ role: UserRole.USER, ++ videoQuota: CONFIG.USER.VIDEO_QUOTA, ++ videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY, ++ emailVerified: true, ++ adminFlags: UserAdminFlag.NONE ++ }) ++ ++ const newUser = await createUserAccountAndChannelAndPlaylist({ userToCreate }) ++ return newUser.user ++ } + if (!user) return null + ++ if (user.username === "invite") return user ++ + const passwordMatch = await user.isPasswordMatch(password) + if (passwordMatch === false) return null + -- 2.41.0