mirror of https://gitlab.crans.org/nounous/nixos
parent
3964004665
commit
b3c0113d8a
|
|
@ -1,3 +1,14 @@
|
||||||
|
diff --git a/sql/postgres/table_wsoauth_multiauth_mappings.sql b/sql/postgres/table_wsoauth_multiauth_mappings.sql
|
||||||
|
index d2917db..b903ba7 100644
|
||||||
|
--- a/sql/postgres/table_wsoauth_multiauth_mappings.sql
|
||||||
|
+++ b/sql/postgres/table_wsoauth_multiauth_mappings.sql
|
||||||
|
@@ -1,5 +1,5 @@
|
||||||
|
CREATE TABLE /*_*/wsoauth_multiauth_mappings (
|
||||||
|
- wsoauth_user int unsigned NOT NULL,
|
||||||
|
+ wsoauth_user int NOT NULL,
|
||||||
|
wsoauth_remote_name varchar(512) NOT NULL,
|
||||||
|
wsoauth_provider_id varchar(255) NOT NULL,
|
||||||
|
PRIMARY KEY (wsoauth_remote_name, wsoauth_provider_id)
|
||||||
diff --git a/src/WSOAuth.php b/src/WSOAuth.php
|
diff --git a/src/WSOAuth.php b/src/WSOAuth.php
|
||||||
index 3a94c87..e077b9e 100644
|
index 3a94c87..e077b9e 100644
|
||||||
--- a/src/WSOAuth.php
|
--- a/src/WSOAuth.php
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,852 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
|
||||||
|
inherit (lib)
|
||||||
|
mkDefault
|
||||||
|
mkEnableOption
|
||||||
|
mkPackageOption
|
||||||
|
mkForce
|
||||||
|
mkIf
|
||||||
|
mkMerge
|
||||||
|
mkOption
|
||||||
|
;
|
||||||
|
inherit (lib)
|
||||||
|
concatStringsSep
|
||||||
|
literalExpression
|
||||||
|
mapAttrsToList
|
||||||
|
optional
|
||||||
|
optionals
|
||||||
|
optionalString
|
||||||
|
types
|
||||||
|
;
|
||||||
|
|
||||||
|
cfg = config.services.mediawiki;
|
||||||
|
fpm = config.services.phpfpm.pools.mediawiki;
|
||||||
|
user = "mediawiki";
|
||||||
|
group =
|
||||||
|
if cfg.webserver == "apache" then
|
||||||
|
config.services.httpd.group
|
||||||
|
else if cfg.webserver == "nginx" then
|
||||||
|
config.services.nginx.group
|
||||||
|
else
|
||||||
|
"mediawiki";
|
||||||
|
|
||||||
|
cacheDir = "/var/cache/mediawiki";
|
||||||
|
stateDir = "/var/lib/mediawiki";
|
||||||
|
|
||||||
|
toolsPath = pkgs.symlinkJoin {
|
||||||
|
name = "mediawiki-path";
|
||||||
|
paths = cfg.path;
|
||||||
|
};
|
||||||
|
|
||||||
|
pkg = pkgs.stdenv.mkDerivation rec {
|
||||||
|
pname = "mediawiki-full";
|
||||||
|
inherit (src) version;
|
||||||
|
src = cfg.package;
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out
|
||||||
|
cp -r * $out/
|
||||||
|
|
||||||
|
substituteInPlace $out/share/mediawiki/includes/config-schema.php \
|
||||||
|
--replace-fail "/usr/bin/" "${toolsPath}/bin/" \
|
||||||
|
--replace-fail "\$path/" "${toolsPath}/bin/"
|
||||||
|
|
||||||
|
# try removing directories before symlinking to allow overwriting any builtin extension or skin
|
||||||
|
${concatStringsSep "\n" (
|
||||||
|
mapAttrsToList (k: v: ''
|
||||||
|
rm -rf $out/share/mediawiki/skins/${k}
|
||||||
|
ln -s ${v} $out/share/mediawiki/skins/${k}
|
||||||
|
'') cfg.skins
|
||||||
|
)}
|
||||||
|
|
||||||
|
${concatStringsSep "\n" (
|
||||||
|
mapAttrsToList (k: v: ''
|
||||||
|
rm -rf $out/share/mediawiki/extensions/${k}
|
||||||
|
ln -s ${
|
||||||
|
if v != null then v else "$src/share/mediawiki/extensions/${k}"
|
||||||
|
} $out/share/mediawiki/extensions/${k}
|
||||||
|
'') cfg.extensions
|
||||||
|
)}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
mediawikiScripts =
|
||||||
|
pkgs.runCommand "mediawiki-scripts"
|
||||||
|
{
|
||||||
|
nativeBuildInputs = [ pkgs.makeWrapper ];
|
||||||
|
preferLocalBuild = true;
|
||||||
|
}
|
||||||
|
''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
makeWrapper ${cfg.phpPackage}/bin/php $out/bin/mediawiki-maintenance \
|
||||||
|
--set MEDIAWIKI_CONFIG ${mediawikiConfig} \
|
||||||
|
--add-flags ${pkg}/share/mediawiki/maintenance/run.php
|
||||||
|
|
||||||
|
for i in changePassword createAndPromote deleteUserEmail renameUser resetUserEmail userOptions edit nukePage update importDump run; do
|
||||||
|
script="$out/bin/mediawiki-$i"
|
||||||
|
cat <<'EOF' >"$script"
|
||||||
|
#!${pkgs.runtimeShell}
|
||||||
|
become=(exec)
|
||||||
|
if [[ "$(id -u)" != ${user} ]]; then
|
||||||
|
become=(exec /run/wrappers/bin/sudo -u ${user} --)
|
||||||
|
fi
|
||||||
|
"${"$"}{become[@]}" ${placeholder "out"}/bin/mediawiki-maintenance \
|
||||||
|
EOF
|
||||||
|
if [[ "$i" != "run" ]]; then
|
||||||
|
echo " ${pkg}/share/mediawiki/maintenance/$i.php \"\$@\"" >>"$script"
|
||||||
|
else
|
||||||
|
echo " ${pkg}/share/mediawiki/maintenance/\$1.php \"\''${@:2}\"" >>"$script"
|
||||||
|
fi
|
||||||
|
chmod +x "$script"
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
|
||||||
|
dbAddr =
|
||||||
|
if cfg.database.type == "postgres" then
|
||||||
|
"${if cfg.database.socket == null then cfg.database.host else cfg.database.socket}"
|
||||||
|
else if cfg.database.socket == null then
|
||||||
|
"${cfg.database.host}:${toString cfg.database.port}"
|
||||||
|
else if cfg.database.type == "mysql" then
|
||||||
|
"${cfg.database.host}:${cfg.database.socket}"
|
||||||
|
else
|
||||||
|
throw "Unsupported database type: ${cfg.database.type} for socket: ${cfg.database.socket}";
|
||||||
|
|
||||||
|
mediawikiConfig = pkgs.writeTextFile {
|
||||||
|
name = "LocalSettings.php";
|
||||||
|
checkPhase = ''
|
||||||
|
${cfg.phpPackage}/bin/php --syntax-check "$target"
|
||||||
|
'';
|
||||||
|
text =
|
||||||
|
let
|
||||||
|
dbSettings =
|
||||||
|
if cfg.database.type == "sqlite" then
|
||||||
|
''
|
||||||
|
$wgSQLiteDataDir = "${cfg.database.path}";
|
||||||
|
''
|
||||||
|
else
|
||||||
|
''
|
||||||
|
$wgDBserver = "${dbAddr}";
|
||||||
|
$wgDBport = "${toString cfg.database.port}";
|
||||||
|
$wgDBuser = "${cfg.database.user}";
|
||||||
|
${optionalString (
|
||||||
|
cfg.database.passwordFile != null
|
||||||
|
) "$wgDBpassword = file_get_contents(\"${cfg.database.passwordFile}\");"}
|
||||||
|
|
||||||
|
${optionalString (cfg.database.type == "mysql" && cfg.database.tablePrefix != null) ''
|
||||||
|
# MySQL specific settings
|
||||||
|
$wgDBprefix = "${cfg.database.tablePrefix}";
|
||||||
|
''}
|
||||||
|
|
||||||
|
${optionalString (cfg.database.type == "mysql") ''
|
||||||
|
# MySQL table options to use during installation or update
|
||||||
|
$wgDBTableOptions = "ENGINE=InnoDB, DEFAULT CHARSET=binary";
|
||||||
|
''}
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
''
|
||||||
|
<?php
|
||||||
|
# Protect against web entry
|
||||||
|
if ( !defined( 'MEDIAWIKI' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$wgSitename = "${cfg.name}";
|
||||||
|
$wgMetaNamespace = false;
|
||||||
|
|
||||||
|
## The URL base path to the directory containing the wiki;
|
||||||
|
## defaults for all runtime URL paths are based off of this.
|
||||||
|
## For more information on customizing the URLs
|
||||||
|
## (like /w/index.php/Page_title to /wiki/Page_title) please see:
|
||||||
|
## https://www.mediawiki.org/wiki/Manual:Short_URL
|
||||||
|
$wgScriptPath = "${lib.optionalString (cfg.webserver == "nginx") "/w"}";
|
||||||
|
|
||||||
|
## The protocol and server name to use in fully-qualified URLs
|
||||||
|
$wgServer = "${cfg.url}";
|
||||||
|
|
||||||
|
## The URL path to static resources (images, scripts, etc.)
|
||||||
|
$wgResourceBasePath = $wgScriptPath;
|
||||||
|
|
||||||
|
${lib.optionalString (cfg.webserver == "nginx") ''
|
||||||
|
$wgArticlePath = "/wiki/$1";
|
||||||
|
$wgUsePathInfo = true;
|
||||||
|
''}
|
||||||
|
|
||||||
|
## The URL path to the logo. Make sure you change this from the default,
|
||||||
|
## or else you'll overwrite your logo when you upgrade!
|
||||||
|
$wgLogo = "$wgResourceBasePath/resources/assets/wiki.png";
|
||||||
|
|
||||||
|
## UPO means: this is also a user preference option
|
||||||
|
|
||||||
|
$wgEnableEmail = true;
|
||||||
|
$wgEnableUserEmail = true; # UPO
|
||||||
|
|
||||||
|
$wgPasswordSender = "${cfg.passwordSender}";
|
||||||
|
|
||||||
|
$wgEnotifUserTalk = false; # UPO
|
||||||
|
$wgEnotifWatchlist = false; # UPO
|
||||||
|
$wgEmailAuthentication = true;
|
||||||
|
|
||||||
|
## Database settings
|
||||||
|
$wgDBtype = "${cfg.database.type}";
|
||||||
|
$wgDBname = "${cfg.database.name}";
|
||||||
|
${dbSettings}
|
||||||
|
|
||||||
|
## Shared memory settings
|
||||||
|
$wgMainCacheType = CACHE_NONE;
|
||||||
|
$wgMemCachedServers = [];
|
||||||
|
|
||||||
|
${optionalString (cfg.uploadsDir != null) ''
|
||||||
|
$wgEnableUploads = true;
|
||||||
|
$wgUploadDirectory = "${cfg.uploadsDir}";
|
||||||
|
''}
|
||||||
|
|
||||||
|
$wgUseImageMagick = true;
|
||||||
|
|
||||||
|
# InstantCommons allows wiki to use images from https://commons.wikimedia.org
|
||||||
|
$wgUseInstantCommons = false;
|
||||||
|
|
||||||
|
# Periodically send a pingback to https://www.mediawiki.org/ with basic data
|
||||||
|
# about this MediaWiki instance. The Wikimedia Foundation shares this data
|
||||||
|
# with MediaWiki developers to help guide future development efforts.
|
||||||
|
$wgPingback = true;
|
||||||
|
|
||||||
|
## If you use ImageMagick (or any other shell command) on a
|
||||||
|
## Linux server, this will need to be set to the name of an
|
||||||
|
## available UTF-8 locale
|
||||||
|
$wgShellLocale = "C.UTF-8";
|
||||||
|
|
||||||
|
## Set $wgCacheDirectory to a writable directory on the web server
|
||||||
|
## to make your wiki go slightly faster. The directory should not
|
||||||
|
## be publicly accessible from the web.
|
||||||
|
$wgCacheDirectory = "${cacheDir}";
|
||||||
|
|
||||||
|
# Site language code, should be one of the list in ./languages/data/Names.php
|
||||||
|
$wgLanguageCode = "en";
|
||||||
|
|
||||||
|
$wgSecretKey = file_get_contents("${stateDir}/secret.key");
|
||||||
|
|
||||||
|
# Changing this will log out all existing sessions.
|
||||||
|
$wgAuthenticationTokenVersion = "";
|
||||||
|
|
||||||
|
## For attaching licensing metadata to pages, and displaying an
|
||||||
|
## appropriate copyright notice / icon. GNU Free Documentation
|
||||||
|
## License and Creative Commons licenses are supported so far.
|
||||||
|
$wgRightsPage = ""; # Set to the title of a wiki page that describes your license/copyright
|
||||||
|
$wgRightsUrl = "";
|
||||||
|
$wgRightsText = "";
|
||||||
|
$wgRightsIcon = "";
|
||||||
|
|
||||||
|
# Enable APCU caching
|
||||||
|
$wgMainCacheType = CACHE_ACCEL;
|
||||||
|
|
||||||
|
# Enabled skins.
|
||||||
|
${concatStringsSep "\n" (mapAttrsToList (k: v: "wfLoadSkin('${k}');") cfg.skins)}
|
||||||
|
|
||||||
|
# Enabled extensions.
|
||||||
|
${concatStringsSep "\n" (mapAttrsToList (k: v: "wfLoadExtension('${k}');") cfg.extensions)}
|
||||||
|
|
||||||
|
|
||||||
|
# End of automatically generated settings.
|
||||||
|
# Add more configuration options below.
|
||||||
|
|
||||||
|
${cfg.extraConfig}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
withTrailingSlash = str: if lib.hasSuffix "/" str then str else "${str}/";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options = {
|
||||||
|
services.mediawiki = {
|
||||||
|
|
||||||
|
enable = mkEnableOption "MediaWiki";
|
||||||
|
|
||||||
|
package = mkPackageOption pkgs "mediawiki" { };
|
||||||
|
|
||||||
|
# https://www.mediawiki.org/wiki/Compatibility#PHP
|
||||||
|
phpPackage = mkPackageOption pkgs "php" { } // {
|
||||||
|
default = pkgs.php83.buildEnv {
|
||||||
|
extensions = { all, enabled }: enabled ++ (with all; [ apcu ]);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
finalPackage = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
readOnly = true;
|
||||||
|
default = pkg;
|
||||||
|
defaultText = literalExpression "pkg";
|
||||||
|
description = ''
|
||||||
|
The final package used by the module. This is the package that will have extensions and skins installed.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
name = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "MediaWiki";
|
||||||
|
example = "Foobar Wiki";
|
||||||
|
description = "Name of the wiki.";
|
||||||
|
};
|
||||||
|
|
||||||
|
url = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default =
|
||||||
|
if cfg.webserver == "apache" then
|
||||||
|
"${
|
||||||
|
if
|
||||||
|
cfg.httpd.virtualHost.addSSL || cfg.httpd.virtualHost.forceSSL || cfg.httpd.virtualHost.onlySSL
|
||||||
|
then
|
||||||
|
"https"
|
||||||
|
else
|
||||||
|
"http"
|
||||||
|
}://${cfg.httpd.virtualHost.hostName}"
|
||||||
|
else if cfg.webserver == "nginx" then
|
||||||
|
let
|
||||||
|
hasSSL = host: host.forceSSL || host.addSSL;
|
||||||
|
in
|
||||||
|
"${
|
||||||
|
if hasSSL config.services.nginx.virtualHosts.${cfg.nginx.hostName} then "https" else "http"
|
||||||
|
}://${cfg.nginx.hostName}"
|
||||||
|
else
|
||||||
|
"http://localhost";
|
||||||
|
defaultText = ''
|
||||||
|
if "mediawiki uses ssl" then "{"https" else "http"}://''${cfg.hostName}" else "http://localhost";
|
||||||
|
'';
|
||||||
|
example = "https://wiki.example.org";
|
||||||
|
description = "URL of the wiki.";
|
||||||
|
};
|
||||||
|
|
||||||
|
uploadsDir = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default = "${stateDir}/uploads";
|
||||||
|
description = ''
|
||||||
|
This directory is used for uploads of pictures. The directory passed here is automatically
|
||||||
|
created and permissions adjusted as required.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
passwordFile = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
description = ''
|
||||||
|
A file containing the initial password for the administrator account "admin".
|
||||||
|
'';
|
||||||
|
example = "/run/keys/mediawiki-password";
|
||||||
|
};
|
||||||
|
|
||||||
|
passwordSender = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default =
|
||||||
|
if cfg.webserver == "apache" then
|
||||||
|
if cfg.httpd.virtualHost.adminAddr != null then
|
||||||
|
cfg.httpd.virtualHost.adminAddr
|
||||||
|
else
|
||||||
|
config.services.httpd.adminAddr
|
||||||
|
else
|
||||||
|
"root@localhost";
|
||||||
|
defaultText = literalExpression ''
|
||||||
|
if cfg.webserver == "apache" then
|
||||||
|
if cfg.httpd.virtualHost.adminAddr != null then
|
||||||
|
cfg.httpd.virtualHost.adminAddr
|
||||||
|
else
|
||||||
|
config.services.httpd.adminAddr else "root@localhost"
|
||||||
|
'';
|
||||||
|
description = "Contact address for password reset.";
|
||||||
|
};
|
||||||
|
|
||||||
|
path = mkOption {
|
||||||
|
type = types.listOf types.package;
|
||||||
|
defaultText = lib.literalExpression "with pkgs; [ diffutils imagemagick ]";
|
||||||
|
example = lib.literalExpression "with pkgs; [ librsvg ]";
|
||||||
|
description = "Extra packages to add to the PATH of phpfpm-pool.";
|
||||||
|
};
|
||||||
|
|
||||||
|
skins = mkOption {
|
||||||
|
default = { };
|
||||||
|
type = types.attrsOf types.path;
|
||||||
|
description = ''
|
||||||
|
Attribute set of paths whose content is copied to the {file}`skins`
|
||||||
|
subdirectory of the MediaWiki installation in addition to the default skins.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extensions = mkOption {
|
||||||
|
default = { };
|
||||||
|
type = types.attrsOf (types.nullOr types.path);
|
||||||
|
description = ''
|
||||||
|
Attribute set of paths whose content is copied to the {file}`extensions`
|
||||||
|
subdirectory of the MediaWiki installation and enabled in configuration.
|
||||||
|
|
||||||
|
Use `null` instead of path to enable extensions that are part of MediaWiki.
|
||||||
|
'';
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
Matomo = pkgs.fetchzip {
|
||||||
|
url = "https://github.com/DaSchTour/matomo-mediawiki-extension/archive/v4.0.1.tar.gz";
|
||||||
|
sha256 = "0g5rd3zp0avwlmqagc59cg9bbkn3r7wx7p6yr80s644mj6dlvs1b";
|
||||||
|
};
|
||||||
|
ParserFunctions = null;
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
webserver = mkOption {
|
||||||
|
type = types.enum [
|
||||||
|
"apache"
|
||||||
|
"none"
|
||||||
|
"nginx"
|
||||||
|
];
|
||||||
|
default = "apache";
|
||||||
|
description = "Webserver to use.";
|
||||||
|
};
|
||||||
|
|
||||||
|
database = {
|
||||||
|
type = mkOption {
|
||||||
|
type = types.enum [
|
||||||
|
"mysql"
|
||||||
|
"postgres"
|
||||||
|
"mssql"
|
||||||
|
"oracle"
|
||||||
|
"sqlite"
|
||||||
|
];
|
||||||
|
default = "mysql";
|
||||||
|
description = "Database engine to use. MySQL/MariaDB is the database of choice by MediaWiki developers.";
|
||||||
|
};
|
||||||
|
|
||||||
|
host = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = if cfg.database.type == "sqlite" then null else "localhost";
|
||||||
|
defaultText = ''"localhost"'';
|
||||||
|
description = "Database host address. Used only if database type is not SQLite.";
|
||||||
|
};
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = types.nullOr types.port;
|
||||||
|
default =
|
||||||
|
if cfg.database.type == "mysql" then
|
||||||
|
3306
|
||||||
|
else if cfg.database.type != "sqlite" then
|
||||||
|
5432
|
||||||
|
else
|
||||||
|
null;
|
||||||
|
defaultText = literalExpression "3306";
|
||||||
|
description = "Database host port. Used only if database type is not SQLite.";
|
||||||
|
};
|
||||||
|
|
||||||
|
name = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "mediawiki";
|
||||||
|
description = "Database name.";
|
||||||
|
};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = if cfg.database.type != "sqlite" then "mediawiki" else null;
|
||||||
|
defaultText = literalExpression ''"mediawiki"'';
|
||||||
|
description = "Database user. Used only if database type is not SQLite.";
|
||||||
|
};
|
||||||
|
|
||||||
|
path = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default = if cfg.database.type == "sqlite" then "${stateDir}/data" else null;
|
||||||
|
defaultText = literalExpression ''"${stateDir}/data"'';
|
||||||
|
description = "Path to store the MediaWiki database in if using SQLite.";
|
||||||
|
};
|
||||||
|
|
||||||
|
passwordFile = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default = null;
|
||||||
|
example = "/run/keys/mediawiki-dbpassword";
|
||||||
|
description = ''
|
||||||
|
A file containing the password corresponding to
|
||||||
|
{option}`database.user`. Used only if database type is not SQLite.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
tablePrefix = mkOption {
|
||||||
|
type = types.nullOr types.str;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
If you only have access to a single database and wish to install more than
|
||||||
|
one version of MediaWiki, or have other applications that also use the
|
||||||
|
database, you can give the table names a unique prefix to stop any naming
|
||||||
|
conflicts or confusion. Only used if database type is MySQL.
|
||||||
|
See <https://www.mediawiki.org/wiki/Manual:$wgDBprefix>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
socket = mkOption {
|
||||||
|
type = types.nullOr types.path;
|
||||||
|
default =
|
||||||
|
if (cfg.database.type == "mysql" && cfg.database.createLocally) then
|
||||||
|
"/run/mysqld/mysqld.sock"
|
||||||
|
else if (cfg.database.type == "postgres" && cfg.database.createLocally) then
|
||||||
|
"/run/postgresql"
|
||||||
|
else
|
||||||
|
null;
|
||||||
|
defaultText = literalExpression "/run/mysqld/mysqld.sock";
|
||||||
|
description = "Path to the unix socket file to use for authentication. Used only if database type is not SQLite.";
|
||||||
|
};
|
||||||
|
|
||||||
|
createLocally = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = cfg.database.type == "mysql" || cfg.database.type == "postgres";
|
||||||
|
defaultText = literalExpression "true";
|
||||||
|
description = ''
|
||||||
|
Create the database and database user locally.
|
||||||
|
This currently only applies if database type "mysql" or "postgres" is selected.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nginx.hostName = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = literalExpression "wiki.example.com";
|
||||||
|
default = "localhost";
|
||||||
|
description = ''
|
||||||
|
The hostname to use for the nginx virtual host.
|
||||||
|
This is used to generate the nginx configuration.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
httpd.virtualHost = mkOption {
|
||||||
|
type = types.submodule { }; # (import ../web-servers/apache-httpd/vhost-options.nix);
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
hostName = "mediawiki.example.org";
|
||||||
|
adminAddr = "webmaster@example.org";
|
||||||
|
forceSSL = true;
|
||||||
|
enableACME = true;
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = ''
|
||||||
|
Apache configuration can be done by adapting {option}`services.httpd.virtualHosts`.
|
||||||
|
See [](#opt-services.httpd.virtualHosts) for further information.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
poolConfig = mkOption {
|
||||||
|
type =
|
||||||
|
with types;
|
||||||
|
attrsOf (oneOf [
|
||||||
|
str
|
||||||
|
int
|
||||||
|
bool
|
||||||
|
]);
|
||||||
|
default = {
|
||||||
|
"pm" = "dynamic";
|
||||||
|
"pm.max_children" = 32;
|
||||||
|
"pm.start_servers" = 2;
|
||||||
|
"pm.min_spare_servers" = 2;
|
||||||
|
"pm.max_spare_servers" = 4;
|
||||||
|
"pm.max_requests" = 500;
|
||||||
|
};
|
||||||
|
description = ''
|
||||||
|
Options for the MediaWiki PHP pool. See the documentation on `php-fpm.conf`
|
||||||
|
for details on configuration directives.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extraConfig = mkOption {
|
||||||
|
type = types.lines;
|
||||||
|
description = ''
|
||||||
|
Any additional text to be appended to MediaWiki's
|
||||||
|
LocalSettings.php configuration file. For configuration
|
||||||
|
settings, see <https://www.mediawiki.org/wiki/Manual:Configuration_settings>.
|
||||||
|
'';
|
||||||
|
default = "";
|
||||||
|
example = ''
|
||||||
|
$wgEnableEmail = false;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
imports = [
|
||||||
|
(lib.mkRenamedOptionModule
|
||||||
|
[ "services" "mediawiki" "virtualHost" ]
|
||||||
|
[ "services" "mediawiki" "httpd" "virtualHost" ]
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion =
|
||||||
|
cfg.database.createLocally -> (cfg.database.type == "mysql" || cfg.database.type == "postgres");
|
||||||
|
message = "services.mediawiki.createLocally is currently only supported for database type 'mysql' and 'postgres'";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion =
|
||||||
|
cfg.database.createLocally -> cfg.database.user == user && cfg.database.name == cfg.database.user;
|
||||||
|
message = "services.mediawiki.database.user must be set to ${user} if services.mediawiki.database.createLocally is set true";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = cfg.database.createLocally -> cfg.database.socket != null;
|
||||||
|
message = "services.mediawiki.database.socket must be set if services.mediawiki.database.createLocally is set to true";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = cfg.database.createLocally -> cfg.database.passwordFile == null;
|
||||||
|
message = "a password cannot be specified if services.mediawiki.database.createLocally is set to true";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
warnings =
|
||||||
|
lib.optional
|
||||||
|
(
|
||||||
|
cfg.database.type == "sqlite"
|
||||||
|
&& (
|
||||||
|
cfg.database.host != null
|
||||||
|
|| cfg.database.port != null
|
||||||
|
|| cfg.database.user != null
|
||||||
|
|| cfg.database.passwordFile != null
|
||||||
|
|| cfg.database.socket != null
|
||||||
|
)
|
||||||
|
)
|
||||||
|
''
|
||||||
|
The services.mediawiki.database options host, port, user, passwordFile, and socket will be ignored because services.mediawiki.database.type is "sqlite".
|
||||||
|
''
|
||||||
|
++ lib.optional (cfg.database.type != "sqlite" && cfg.database.path != null) ''
|
||||||
|
The services.mediawiki.database.path option will be ignored because services.mediawiki.database.type is not "sqlite".
|
||||||
|
''
|
||||||
|
++ lib.optional (cfg.database.type != "mysql" && cfg.database.tablePrefix != null) ''
|
||||||
|
The services.mediawiki.database.tablePrefix option has no effect when the services.mediawiki.database.type is not "mysql".
|
||||||
|
'';
|
||||||
|
|
||||||
|
services.mediawiki = {
|
||||||
|
path = with pkgs; [
|
||||||
|
diffutils
|
||||||
|
imagemagick
|
||||||
|
];
|
||||||
|
skins = {
|
||||||
|
MonoBook = "${cfg.package}/share/mediawiki/skins/MonoBook";
|
||||||
|
Timeless = "${cfg.package}/share/mediawiki/skins/Timeless";
|
||||||
|
Vector = "${cfg.package}/share/mediawiki/skins/Vector";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.mysql = mkIf (cfg.database.type == "mysql" && cfg.database.createLocally) {
|
||||||
|
enable = true;
|
||||||
|
package = mkDefault pkgs.mariadb;
|
||||||
|
ensureDatabases = [ cfg.database.name ];
|
||||||
|
ensureUsers = [
|
||||||
|
{
|
||||||
|
name = cfg.database.user;
|
||||||
|
ensurePermissions = {
|
||||||
|
"${cfg.database.name}.*" = "ALL PRIVILEGES";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.postgresql = mkIf (cfg.database.type == "postgres" && cfg.database.createLocally) {
|
||||||
|
enable = true;
|
||||||
|
ensureDatabases = [ cfg.database.name ];
|
||||||
|
ensureUsers = [
|
||||||
|
{
|
||||||
|
name = cfg.database.user;
|
||||||
|
ensureDBOwnership = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.phpfpm.pools.mediawiki = {
|
||||||
|
inherit user group;
|
||||||
|
phpEnv.MEDIAWIKI_CONFIG = "${mediawikiConfig}";
|
||||||
|
phpPackage = cfg.phpPackage;
|
||||||
|
settings =
|
||||||
|
(
|
||||||
|
if (cfg.webserver == "apache") then
|
||||||
|
{
|
||||||
|
"listen.owner" = config.services.httpd.user;
|
||||||
|
"listen.group" = config.services.httpd.group;
|
||||||
|
}
|
||||||
|
else if (cfg.webserver == "nginx") then
|
||||||
|
{
|
||||||
|
"listen.owner" = config.services.nginx.user;
|
||||||
|
"listen.group" = config.services.nginx.group;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
"listen.owner" = user;
|
||||||
|
"listen.group" = group;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
// cfg.poolConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.httpd = lib.mkIf (cfg.webserver == "apache") {
|
||||||
|
enable = true;
|
||||||
|
extraModules = [ "proxy_fcgi" ];
|
||||||
|
virtualHosts.${cfg.httpd.virtualHost.hostName} = mkMerge [
|
||||||
|
cfg.httpd.virtualHost
|
||||||
|
{
|
||||||
|
documentRoot = mkForce "${pkg}/share/mediawiki";
|
||||||
|
extraConfig = ''
|
||||||
|
<Directory "${pkg}/share/mediawiki">
|
||||||
|
<FilesMatch "\.php$">
|
||||||
|
<If "-f %{REQUEST_FILENAME}">
|
||||||
|
SetHandler "proxy:unix:${fpm.socket}|fcgi://localhost/"
|
||||||
|
</If>
|
||||||
|
</FilesMatch>
|
||||||
|
|
||||||
|
Require all granted
|
||||||
|
DirectoryIndex index.php
|
||||||
|
AllowOverride All
|
||||||
|
</Directory>
|
||||||
|
''
|
||||||
|
+ optionalString (cfg.uploadsDir != null) ''
|
||||||
|
Alias "/images" "${cfg.uploadsDir}"
|
||||||
|
<Directory "${cfg.uploadsDir}">
|
||||||
|
Require all granted
|
||||||
|
</Directory>
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
# inspired by https://www.mediawiki.org/wiki/Manual:Short_URL/Nginx
|
||||||
|
services.nginx = lib.mkIf (cfg.webserver == "nginx") {
|
||||||
|
enable = true;
|
||||||
|
virtualHosts.${config.services.mediawiki.nginx.hostName} = {
|
||||||
|
root = "${pkg}/share/mediawiki";
|
||||||
|
locations = {
|
||||||
|
"~ ^/w/(index|load|api|thumb|opensearch_desc|rest|img_auth)\\.php$".extraConfig = ''
|
||||||
|
rewrite ^/w/(.*) /$1 break;
|
||||||
|
include ${config.services.nginx.package}/conf/fastcgi.conf;
|
||||||
|
fastcgi_index index.php;
|
||||||
|
fastcgi_pass unix:${config.services.phpfpm.pools.mediawiki.socket};
|
||||||
|
'';
|
||||||
|
"/w/images/".alias = withTrailingSlash cfg.uploadsDir;
|
||||||
|
# Deny access to deleted images folder
|
||||||
|
"/w/images/deleted".extraConfig = ''
|
||||||
|
deny all;
|
||||||
|
'';
|
||||||
|
# MediaWiki assets (usually images)
|
||||||
|
"~ ^/w/resources/(assets|lib|src)".extraConfig = ''
|
||||||
|
rewrite ^/w(/.*) $1 break;
|
||||||
|
add_header Cache-Control "public";
|
||||||
|
expires 7d;
|
||||||
|
'';
|
||||||
|
# Assets, scripts and styles from skins and extensions
|
||||||
|
"~ ^/w/(skins|extensions)/.+\\.(css|js|gif|jpg|jpeg|png|svg|wasm|ttf|woff|woff2)$".extraConfig = ''
|
||||||
|
rewrite ^/w(/.*) $1 break;
|
||||||
|
add_header Cache-Control "public";
|
||||||
|
expires 7d;
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Handling for Mediawiki REST API, see [[mw:API:REST_API]]
|
||||||
|
"/w/rest.php/".tryFiles = "$uri $uri/ /w/rest.php?$query_string";
|
||||||
|
|
||||||
|
# Handling for the article path (pretty URLs)
|
||||||
|
"/wiki/".extraConfig = ''
|
||||||
|
rewrite ^/wiki/(?<pagename>.*)$ /w/index.php;
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Explicit access to the root website, redirect to main page (adapt as needed)
|
||||||
|
"= /".extraConfig = ''
|
||||||
|
return 301 /wiki/;
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Every other entry point will be disallowed.
|
||||||
|
# Add specific rules for other entry points/images as needed above this
|
||||||
|
"/".extraConfig = ''
|
||||||
|
return 404;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d '${stateDir}' 0750 ${user} ${group} - -"
|
||||||
|
"d '${cacheDir}' 0750 ${user} ${group} - -"
|
||||||
|
]
|
||||||
|
++ optionals (cfg.uploadsDir != null) [
|
||||||
|
"d '${cfg.uploadsDir}' 0750 ${user} ${group} - -"
|
||||||
|
"Z '${cfg.uploadsDir}' 0750 ${user} ${group} - -"
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.services.mediawiki-init = {
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
before = [ "phpfpm-mediawiki.service" ];
|
||||||
|
after =
|
||||||
|
optional (cfg.database.type == "mysql" && cfg.database.createLocally) "mysql.service"
|
||||||
|
++ optional (cfg.database.type == "postgres" && cfg.database.createLocally) "postgresql.target";
|
||||||
|
script =
|
||||||
|
let
|
||||||
|
dbOptions =
|
||||||
|
if cfg.database.type == "sqlite" then
|
||||||
|
''
|
||||||
|
--dbpath ${lib.escapeShellArg cfg.database.path} \
|
||||||
|
--dbname ${lib.escapeShellArg cfg.database.name} \
|
||||||
|
''
|
||||||
|
else
|
||||||
|
''
|
||||||
|
--dbserver ${lib.escapeShellArg dbAddr} \
|
||||||
|
--dbport ${toString cfg.database.port} \
|
||||||
|
--dbname ${lib.escapeShellArg cfg.database.name} \
|
||||||
|
${
|
||||||
|
optionalString (
|
||||||
|
cfg.database.tablePrefix != null
|
||||||
|
) "--dbprefix ${lib.escapeShellArg cfg.database.tablePrefix}"
|
||||||
|
} \
|
||||||
|
--dbuser ${lib.escapeShellArg cfg.database.user} \
|
||||||
|
${
|
||||||
|
optionalString (
|
||||||
|
cfg.database.passwordFile != null
|
||||||
|
) "--dbpassfile ${lib.escapeShellArg cfg.database.passwordFile}"
|
||||||
|
} \
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
''
|
||||||
|
if ! test -e "${stateDir}/secret.key"; then
|
||||||
|
tr -dc A-Za-z0-9 </dev/urandom 2>/dev/null | head -c 64 > ${stateDir}/secret.key
|
||||||
|
fi
|
||||||
|
|
||||||
|
${optionalString (cfg.database.type == "sqlite") "mkdir -p ${cfg.database.path}"}
|
||||||
|
|
||||||
|
echo "exit( \$this->getPrimaryDB()->tableExists( 'user' ) ? 1 : 0 );" | \
|
||||||
|
${cfg.phpPackage}/bin/php ${pkg}/share/mediawiki/maintenance/run.php eval --conf ${mediawikiConfig} && \
|
||||||
|
${cfg.phpPackage}/bin/php ${pkg}/share/mediawiki/maintenance/run.php ${pkg}/share/mediawiki/maintenance/install.php \
|
||||||
|
--confpath /tmp \
|
||||||
|
--scriptpath / \
|
||||||
|
${dbOptions} \
|
||||||
|
--dbtype ${cfg.database.type} \
|
||||||
|
--passfile ${lib.escapeShellArg cfg.passwordFile} \
|
||||||
|
${lib.escapeShellArg cfg.name} \
|
||||||
|
admin
|
||||||
|
|
||||||
|
${cfg.phpPackage}/bin/php ${pkg}/share/mediawiki/maintenance/update.php --conf ${mediawikiConfig} --quick --skip-external-dependencies
|
||||||
|
'';
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
User = user;
|
||||||
|
Group = group;
|
||||||
|
PrivateTmp = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.httpd.after =
|
||||||
|
optional (
|
||||||
|
cfg.webserver == "apache" && cfg.database.createLocally && cfg.database.type == "mysql"
|
||||||
|
) "mysql.service"
|
||||||
|
++ optional (
|
||||||
|
cfg.webserver == "apache" && cfg.database.createLocally && cfg.database.type == "postgres"
|
||||||
|
) "postgresql.target";
|
||||||
|
|
||||||
|
users.users.${user} = {
|
||||||
|
inherit group;
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
users.groups.${group} = { };
|
||||||
|
|
||||||
|
environment.systemPackages = [ mediawikiScripts ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -8,6 +8,10 @@ let
|
||||||
phpExtensions = config.services.mediawiki.phpPackage.extensions;
|
phpExtensions = config.services.mediawiki.phpPackage.extensions;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
|
# Mauvaise config posgresql, on fixe à la mano temporairement
|
||||||
|
disabledModules = [ "services/web-apps/mediawiki.nix" ];
|
||||||
|
imports = [ ./mediawiki-patch.nix ];
|
||||||
|
|
||||||
age.secrets.mediawiki-admin-passwd = {
|
age.secrets.mediawiki-admin-passwd = {
|
||||||
file = ../../../secrets/mediakiwi/mediawiki-admin-passwd.age;
|
file = ../../../secrets/mediakiwi/mediawiki-admin-passwd.age;
|
||||||
owner = "mediawiki";
|
owner = "mediawiki";
|
||||||
|
|
@ -23,6 +27,7 @@ in
|
||||||
owner = "mediawiki";
|
owner = "mediawiki";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Attention : il ne faut pas mettre de retour à la ligne à la fin du mot de passe !
|
||||||
age.secrets.mediawiki-db = {
|
age.secrets.mediawiki-db = {
|
||||||
file = ../../../secrets/mediakiwi/mediawiki-db-pass.age;
|
file = ../../../secrets/mediakiwi/mediawiki-db-pass.age;
|
||||||
owner = "mediawiki";
|
owner = "mediawiki";
|
||||||
|
|
@ -302,10 +307,10 @@ in
|
||||||
name = "Popups";
|
name = "Popups";
|
||||||
owner = "wikimedia";
|
owner = "wikimedia";
|
||||||
repo = "mediawiki-extensions-Popups";
|
repo = "mediawiki-extensions-Popups";
|
||||||
rev = "cfe78f2c07fa5cf6edcb109eadd8b4b01df58d92";
|
rev = "82742d6e42750bf5b8000c90fc894b304aa95235";
|
||||||
# Le SHA doit être changé à chaque nouveau commit de traduction.
|
# Le SHA doit être changé à chaque nouveau commit de traduction.
|
||||||
# Pas de meilleure solution à ma connaissance pour suivre les releases.
|
# Pas de meilleure solution à ma connaissance pour suivre les releases.
|
||||||
sha256 = "sha256-lE64Tl0KmUoNHnN2bkNYvhexz5s1wMQ1bDvWSoWTdZU=";
|
sha256 = "sha256-mqiDU7w3B3imMLqoTvwgnyk/vCDWeAiTEX1y4dWmNDk=";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Auth
|
# Auth
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,33 @@
|
||||||
age-encryption.org/v1
|
age-encryption.org/v1
|
||||||
-> ssh-ed25519 ZpDcxw XrXXRdePOdCNAkEtYg5mBAxKKu1EkJOrrD0cUT3JAUc
|
-> ssh-ed25519 ZpDcxw EYeeHlk7G0Ce8Zjz7DOA6umVE58ZNeRb1ao86/romSA
|
||||||
s7VMCZGoJS5BD8v8/JPQxrLw1GYs01uj9LdR6oL9zsM
|
iCLH6+fsNCeM5heK2QFh9kEY44BiDOQ8um4MCNUDeuI
|
||||||
-> piv-p256 ewCc3w A5Qzmn7RYXKT13rdPG6MRWX5nvjAgnbLv7oNqbei2kQJ
|
-> piv-p256 ewCc3w A+QtLSWeA4j0756rlETtyvJRiZR3y70+UMs/X1/u0fqq
|
||||||
lHc9/3C/aD5wzm3AQlYqIddEEBtke478hPSem2pZdvA
|
FslsT1yQ+NNHK8m/eBLWeNcsPu2BnubNO1h/AO95UxY
|
||||||
-> piv-p256 6CL/Pw A+ZT4TG2h/1B1sxTGsz0dk0JI8Aa03rN7JZa7wcLuY2q
|
-> piv-p256 6CL/Pw AxHghSnLJmHJz9rXlP1IQDoigFTkFUQiE7h3c0EMeLsc
|
||||||
WBVW6R65Qm54777ENzWCmIiBKelfF9PjWZEU9QsAPMk
|
bmI1TbflKxJ6Axg/TgDEtCV0pw7tY6V/pMl4CJGjvL8
|
||||||
-> ssh-ed25519 eOAUSg u95RB+i9FQ+k6V4IUXgVGBcDNIfExZxpnNQ13iQtM0s
|
-> ssh-ed25519 eOAUSg TPhT5qmh2Y9b0eBa41uTdIDdZEcDZtR6tEV8Jo1MuCk
|
||||||
rznvSYERswBrYsoBGOzo67vs7wd6FHSZG8YJlAiNYNk
|
gBD5CQlnxMYohS13RvzoDDQeGDhYOEcS18Xv1S/5f+M
|
||||||
-> ssh-rsa REaZBA
|
-> ssh-rsa REaZBA
|
||||||
jX3byskGzK07aZRbZCUnv8ma8Wwnnav1LszzuKjN5ULBem6tVGk33ak2oRVnNfsc
|
NtWXPRN/qPJ5XUZNXt64Rt3brMfbXxP2ARvXo3wpnB0ed0QPnX29OTyVm/O2VNrY
|
||||||
Vj8jHVySN9b+px1SQk/a/7o/717Xejvoa71xeIMacNuvGNr1VgaISF9niKI5J0Gd
|
5jPouFaxWwDBuwyJ/HyJJB5SdrE188u7du/M0Z8l1/H8i2lpkp98XS64AEXkvrHo
|
||||||
O8KSRcRdkxqBdQ+WIVj1KKjabV9kBxxwf6r1CjH4U1sGqpxCvHT98v20DPYrbzpm
|
oWFsRloCWyeIU3m1MtUdqu/c3pnqyiE1SlCnajb6MUUrhDe2CdEEgJxFsIyMwXpW
|
||||||
1rR8R+z9v/d75bCmQ/RCzkAfxNhuQkQ0h1xZYuCnlolnRK2TvFbUAO9CcfKCwgia
|
mkwtHxe9ngVebRLY3vw9OVhtqrKeKrNvSGGCE+IFn6kWuNoGD/rDI52kx76sNa0D
|
||||||
dwj+R8tt+Pcu5LcSatt7tqqm8X3CKbyb4SJxCHZRq8uz7kDJ5pKKqRIpFL1Gv5jc
|
531FFAdsiPt1VKZi0YBaUfRP407sc6rw8R258jFCeYpa58Zud62BWsT0d464gPkD
|
||||||
2jZEK5tZoKEtnymE7T145Dww3hUdK7lx8Upnm825Unr62DLRNY3JzWnsMpVw0Wkn
|
tJQUZecCPRW0jflpVWzqZHIVurtp3Dqjp/oovmMMJ303/ywL0VdZR6PeMndGOkf+
|
||||||
tzbul4wLwIkja5388cmpQgHywrTiqtm7uLCs2AeKY6oq/7afVPf2bkgwW+J7bWfH
|
ame4zqTwOyQoxSkU+62D/KeSzM0QlVqAZhL+lMfYkFCYizZYQZSlLAHi7nF3704W
|
||||||
bDEBavJu/PJa3dYhLR4gdiH3i+rSivbfMbQgfdRCx94liniv2adi6SmpW6dystoL
|
S+nrv+FNNxLYT6zlq0hHokP9fIfUct/eFfMmV2ff9E77Tow/79TpgQnfxxdtJWJG
|
||||||
|
|
||||||
-> ssh-ed25519 J/iReg zCuMlBFN4eVMnh5vHKqvlJlLg6ZcwAy7wHlvVnQABjw
|
-> ssh-ed25519 J/iReg ZAxHEQjYmqQkMFth5Lp344f0JqwfGh4CO6DEG+uMmys
|
||||||
elWuCugOpDB80l/uEOJnNKEem5xoePkyCD3pmELJ8cs
|
qlLlf9eLNNw3/o++6LVpy2Anj3TWkNbcJoJ/rP4JKsI
|
||||||
-> ssh-ed25519 GNhSGw Wv9wMTi6QUexDlbucYb9SGS4jNFNFs+hoWa5u5HGmzY
|
-> ssh-ed25519 GNhSGw 44kEvp1o41BaNRwFnAjKB4K3otIYhN7QN9FgCd+eSQ4
|
||||||
lrswEeBFRfSkHf0hQ4YcEFmV6ytusrk0zdIsMD+QbQ8
|
fqZM/JCIderSDDrxckv4VLZu64Dfx275UVmfKsozpKU
|
||||||
-> ssh-ed25519 eXMAtA 2BfG6GmISd1+jHa9OruAWnNjbOWJ1kSEAABMAWRA/kI
|
-> ssh-ed25519 eXMAtA mPn1SPpt7RkhMBLqUZ4mWGvqNeGtUN+pcA9jjKKGPGU
|
||||||
BB3JmIEP6ALQuB41BKQK2Wp8ZZw4XEnP2Boh7icE+Hw
|
bGyck1ZRHRlzk+HVmL3e99MiVFxjTuC7v/6WHjRjH8A
|
||||||
-> ssh-ed25519 5hXocQ hZbub90RRPk0Vas8CCLwdTFxw9DNLbw3o2YRNrKsxAU
|
-> ssh-ed25519 5hXocQ bT0MsqVcYEcB/ckkuAC0zbH5+pfs4iPso9MHhVUyx2U
|
||||||
VVFz46gOtFCQIQKDeKiuxedT+dt+P9fhY8sTix5uLxY
|
jZQOFmGWnZMtdTS5ePKIvnQFiOVsZTC/A09ZmXzveho
|
||||||
-> ssh-ed25519 bRHVVA pdEbXrfSgJ2rBKLuHXH0LLnKQy8BbTw0siNm5iLglgY
|
-> ssh-ed25519 bRHVVA NSnH4xuAWnDgUIpi+csZOvq0K6u99Dt1IUGDrzZGcgQ
|
||||||
yRe+LVzvN0l13j4u4K3lGrzn+HokcL2kRw91n1/JIEY
|
L9WOetohzpDPAcF/1jGPmWnBhazSDyIU/0or+il2/ug
|
||||||
-> ssh-ed25519 HgW9eA tPNgD0elE7Bqh87hYKRlrU0HPgTHlNyqMEMqQfkhlgQ
|
-> ssh-ed25519 HgW9eA LdB9v8WGmExJffyQa8KuudNr97nyxshWj9j0YMDJKlI
|
||||||
AtAAtoU/DYVBaQJKPwAcAKrr2KXyJ/iyLUV8LFSmCF0
|
0BCRYHWmulVjwtlYUR2Xi4rdnLSRQTLL2jn8N5rubSo
|
||||||
--- nTU2XNZl52MtMZI+39D+eVeoX55RSWRERVgJNKti3Qk
|
--- y4i6KM8sEq07Sx594lC7WX9hEtq9ce4Vm9tTU8loJtc
|
||||||
ÞÐJ`긌ë2Á0RO7»úŠ<cû¬ÔóÁSÁÙ{^<CP–îÎWSúQö<51>åiÎC»‘<C2BB>L’{æÚ%í•›¦˜‚
|
2Õ‹r};‰„Ï,"¾èÃvß&êÀÂd¬¼}™Ž×8Uê_¼¨VY¸µÅn§h€ZúħÈgê`Nf`
|
||||||
Loading…
Reference in New Issue