916 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			916 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
{ config, lib, pkgs, ... }:
 | 
						|
 | 
						|
with lib;
 | 
						|
 | 
						|
let
 | 
						|
  cfg = config.services.codimd;
 | 
						|
 | 
						|
  prettyJSON = conf:
 | 
						|
    pkgs.runCommand "codimd-config.json" { preferLocalBuild = true; } ''
 | 
						|
      echo '${builtins.toJSON conf}' | ${pkgs.jq}/bin/jq \
 | 
						|
        '{production:del(.[]|nulls)|del(.[][]?|nulls)}' > $out
 | 
						|
    '';
 | 
						|
in
 | 
						|
{
 | 
						|
  options.services.codimd = {
 | 
						|
    enable = mkEnableOption "the CodiMD Markdown Editor";
 | 
						|
 | 
						|
    groups = mkOption {
 | 
						|
      type = types.listOf types.str;
 | 
						|
      default = [];
 | 
						|
      description = ''
 | 
						|
        Groups to which the codimd user should be added.
 | 
						|
      '';
 | 
						|
    };
 | 
						|
 | 
						|
    workDir = mkOption {
 | 
						|
      type = types.path;
 | 
						|
      default = "/var/lib/codimd";
 | 
						|
      description = ''
 | 
						|
        Working directory for the CodiMD service.
 | 
						|
      '';
 | 
						|
    };
 | 
						|
 | 
						|
    configuration = {
 | 
						|
      debug = mkEnableOption "debug mode";
 | 
						|
      domain = mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = null;
 | 
						|
        example = "codimd.org";
 | 
						|
        description = ''
 | 
						|
          Domain name for the CodiMD instance.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      urlPath = mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = null;
 | 
						|
        example = "/url/path/to/codimd";
 | 
						|
        description = ''
 | 
						|
          Path under which CodiMD is accessible.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      host = mkOption {
 | 
						|
        type = types.str;
 | 
						|
        default = "localhost";
 | 
						|
        description = ''
 | 
						|
          Address to listen on.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      port = mkOption {
 | 
						|
        type = types.int;
 | 
						|
        default = 3000;
 | 
						|
        example = "80";
 | 
						|
        description = ''
 | 
						|
          Port to listen on.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      path = mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = null;
 | 
						|
        example = "/run/codimd.sock";
 | 
						|
        description = ''
 | 
						|
          Specify where a UNIX domain socket should be placed.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      allowOrigin = mkOption {
 | 
						|
        type = types.listOf types.str;
 | 
						|
        default = [];
 | 
						|
        example = [ "localhost" "codimd.org" ];
 | 
						|
        description = ''
 | 
						|
          List of domains to whitelist.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      useSSL = mkOption {
 | 
						|
        type = types.bool;
 | 
						|
        default = false;
 | 
						|
        description = ''
 | 
						|
          Enable to use SSL server. This will also enable
 | 
						|
          <option>protocolUseSSL</option>.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      hsts = {
 | 
						|
        enable = mkOption {
 | 
						|
          type = types.bool;
 | 
						|
          default = true;
 | 
						|
          description = ''
 | 
						|
            Wheter to enable HSTS if HTTPS is also enabled.
 | 
						|
          '';
 | 
						|
        };
 | 
						|
        maxAgeSeconds = mkOption {
 | 
						|
          type = types.int;
 | 
						|
          default = 31536000;
 | 
						|
          description = ''
 | 
						|
            Max duration for clients to keep the HSTS status.
 | 
						|
          '';
 | 
						|
        };
 | 
						|
        includeSubdomains = mkOption {
 | 
						|
          type = types.bool;
 | 
						|
          default = true;
 | 
						|
          description = ''
 | 
						|
            Whether to include subdomains in HSTS.
 | 
						|
          '';
 | 
						|
        };
 | 
						|
        preload = mkOption {
 | 
						|
          type = types.bool;
 | 
						|
          default = true;
 | 
						|
          description = ''
 | 
						|
            Whether to allow preloading of the site's HSTS status.
 | 
						|
          '';
 | 
						|
        };
 | 
						|
      };
 | 
						|
      csp = mkOption {
 | 
						|
        type = types.nullOr types.attrs;
 | 
						|
        default = null;
 | 
						|
        example = literalExample ''
 | 
						|
          {
 | 
						|
            enable = true;
 | 
						|
            directives = {
 | 
						|
              scriptSrc = "trustworthy.scripts.example.com";
 | 
						|
            };
 | 
						|
            upgradeInsecureRequest = "auto";
 | 
						|
            addDefaults = true;
 | 
						|
          }
 | 
						|
        '';
 | 
						|
        description = ''
 | 
						|
          Specify the Content Security Policy which is passed to Helmet.
 | 
						|
          For configuration details see <link xlink:href="https://helmetjs.github.io/docs/csp/"
 | 
						|
          >https://helmetjs.github.io/docs/csp/</link>.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      protocolUseSSL = mkOption {
 | 
						|
        type = types.bool;
 | 
						|
        default = false;
 | 
						|
        description = ''
 | 
						|
          Enable to use TLS for resource paths.
 | 
						|
          This only applies when <option>domain</option> is set.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      urlAddPort = mkOption {
 | 
						|
        type = types.bool;
 | 
						|
        default = false;
 | 
						|
        description = ''
 | 
						|
          Enable to add the port to callback URLs.
 | 
						|
          This only applies when <option>domain</option> is set
 | 
						|
          and only for ports other than 80 and 443.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      useCDN = mkOption {
 | 
						|
        type = types.bool;
 | 
						|
        default = true;
 | 
						|
        description = ''
 | 
						|
          Whether to use CDN resources or not.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      allowAnonymous = mkOption {
 | 
						|
        type = types.bool;
 | 
						|
        default = true;
 | 
						|
        description = ''
 | 
						|
          Whether to allow anonymous usage.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      allowAnonymousEdits = mkOption {
 | 
						|
        type = types.bool;
 | 
						|
        default = false;
 | 
						|
        description = ''
 | 
						|
          Whether to allow guests to edit existing notes with the `freely' permission,
 | 
						|
          when <option>allowAnonymous</option> is enabled.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      allowFreeURL = mkOption {
 | 
						|
        type = types.bool;
 | 
						|
        default = false;
 | 
						|
        description = ''
 | 
						|
          Whether to allow note creation by accessing a nonexistent note URL.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      defaultPermission = mkOption {
 | 
						|
        type = types.enum [ "freely" "editable" "limited" "locked" "private" ];
 | 
						|
        default = "editable";
 | 
						|
        description = ''
 | 
						|
          Default permissions for notes.
 | 
						|
          This only applies for signed-in users.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      dbURL = mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = null;
 | 
						|
        example = ''
 | 
						|
          postgres://user:pass@host:5432/dbname
 | 
						|
        '';
 | 
						|
        description = ''
 | 
						|
          Specify which database to use.
 | 
						|
          CodiMD supports mysql, postgres, sqlite and mssql.
 | 
						|
          See <link xlink:href="https://sequelize.readthedocs.io/en/v3/">
 | 
						|
          https://sequelize.readthedocs.io/en/v3/</link> for more information.
 | 
						|
          Note: This option overrides <option>db</option>.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      db = mkOption {
 | 
						|
        type = types.attrs;
 | 
						|
        default = {};
 | 
						|
        example = literalExample ''
 | 
						|
          {
 | 
						|
            dialect = "sqlite";
 | 
						|
            storage = "/var/lib/codimd/db.codimd.sqlite";
 | 
						|
          }
 | 
						|
        '';
 | 
						|
        description = ''
 | 
						|
          Specify the configuration for sequelize.
 | 
						|
          CodiMD supports mysql, postgres, sqlite and mssql.
 | 
						|
          See <link xlink:href="https://sequelize.readthedocs.io/en/v3/">
 | 
						|
          https://sequelize.readthedocs.io/en/v3/</link> for more information.
 | 
						|
          Note: This option overrides <option>db</option>.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      sslKeyPath= mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = null;
 | 
						|
        example = "/var/lib/codimd/codimd.key";
 | 
						|
        description = ''
 | 
						|
          Path to the SSL key. Needed when <option>useSSL</option> is enabled.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      sslCertPath = mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = null;
 | 
						|
        example = "/var/lib/codimd/codimd.crt";
 | 
						|
        description = ''
 | 
						|
          Path to the SSL cert. Needed when <option>useSSL</option> is enabled.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      sslCAPath = mkOption {
 | 
						|
        type = types.listOf types.str;
 | 
						|
        default = [];
 | 
						|
        example = [ "/var/lib/codimd/ca.crt" ];
 | 
						|
        description = ''
 | 
						|
          SSL ca chain. Needed when <option>useSSL</option> is enabled.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      dhParamPath = mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = null;
 | 
						|
        example = "/var/lib/codimd/dhparam.pem";
 | 
						|
        description = ''
 | 
						|
          Path to the SSL dh params. Needed when <option>useSSL</option> is enabled.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      tmpPath = mkOption {
 | 
						|
        type = types.str;
 | 
						|
        default = "/tmp";
 | 
						|
        description = ''
 | 
						|
          Path to the temp directory CodiMD should use.
 | 
						|
          Note that <option>serviceConfig.PrivateTmp</option> is enabled for
 | 
						|
          the CodiMD systemd service by default.
 | 
						|
          (Non-canonical paths are relative to CodiMD's base directory)
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      defaultNotePath = mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = "./public/default.md";
 | 
						|
        description = ''
 | 
						|
          Path to the default Note file.
 | 
						|
          (Non-canonical paths are relative to CodiMD's base directory)
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      docsPath = mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = "./public/docs";
 | 
						|
        description = ''
 | 
						|
          Path to the docs directory.
 | 
						|
          (Non-canonical paths are relative to CodiMD's base directory)
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      indexPath = mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = "./public/views/index.ejs";
 | 
						|
        description = ''
 | 
						|
          Path to the index template file.
 | 
						|
          (Non-canonical paths are relative to CodiMD's base directory)
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      hackmdPath = mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = "./public/views/hackmd.ejs";
 | 
						|
        description = ''
 | 
						|
          Path to the hackmd template file.
 | 
						|
          (Non-canonical paths are relative to CodiMD's base directory)
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      errorPath = mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = null;
 | 
						|
        defaultText = "./public/views/error.ejs";
 | 
						|
        description = ''
 | 
						|
          Path to the error template file.
 | 
						|
          (Non-canonical paths are relative to CodiMD's base directory)
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      prettyPath = mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = null;
 | 
						|
        defaultText = "./public/views/pretty.ejs";
 | 
						|
        description = ''
 | 
						|
          Path to the pretty template file.
 | 
						|
          (Non-canonical paths are relative to CodiMD's base directory)
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      slidePath = mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = null;
 | 
						|
        defaultText = "./public/views/slide.hbs";
 | 
						|
        description = ''
 | 
						|
          Path to the slide template file.
 | 
						|
          (Non-canonical paths are relative to CodiMD's base directory)
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      uploadsPath = mkOption {
 | 
						|
        type = types.str;
 | 
						|
        default = "${cfg.workDir}/uploads";
 | 
						|
        defaultText = "/var/lib/codimd/uploads";
 | 
						|
        description = ''
 | 
						|
          Path under which uploaded files are saved.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      sessionName = mkOption {
 | 
						|
        type = types.str;
 | 
						|
        default = "connect.sid";
 | 
						|
        description = ''
 | 
						|
          Specify the name of the session cookie.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      sessionSecret = mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = null;
 | 
						|
        description = ''
 | 
						|
          Specify the secret used to sign the session cookie.
 | 
						|
          If unset, one will be generated on startup.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      sessionLife = mkOption {
 | 
						|
        type = types.int;
 | 
						|
        default = 1209600000;
 | 
						|
        description = ''
 | 
						|
          Session life time in milliseconds.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      heartbeatInterval = mkOption {
 | 
						|
        type = types.int;
 | 
						|
        default = 5000;
 | 
						|
        description = ''
 | 
						|
          Specify the socket.io heartbeat interval.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      heartbeatTimeout = mkOption {
 | 
						|
        type = types.int;
 | 
						|
        default = 10000;
 | 
						|
        description = ''
 | 
						|
          Specify the socket.io heartbeat timeout.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      documentMaxLength = mkOption {
 | 
						|
        type = types.int;
 | 
						|
        default = 100000;
 | 
						|
        description = ''
 | 
						|
          Specify the maximum document length.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      email = mkOption {
 | 
						|
        type = types.bool;
 | 
						|
        default = true;
 | 
						|
        description = ''
 | 
						|
          Whether to enable email sign-in.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      allowEmailRegister = mkOption {
 | 
						|
        type = types.bool;
 | 
						|
        default = true;
 | 
						|
        description = ''
 | 
						|
          Wether to enable email registration.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      allowGravatar = mkOption {
 | 
						|
        type = types.bool;
 | 
						|
        default = true;
 | 
						|
        description = ''
 | 
						|
          Whether to use gravatar as profile picture source.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      imageUploadType = mkOption {
 | 
						|
        type = types.enum [ "imgur" "s3" "minio" "filesystem" ];
 | 
						|
        default = "filesystem";
 | 
						|
        description = ''
 | 
						|
          Specify where to upload images.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      minio = mkOption {
 | 
						|
        type = types.nullOr (types.submodule {
 | 
						|
          options = {
 | 
						|
            accessKey = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Minio access key.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            secretKey = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Minio secret key.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            endpoint = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Minio endpoint.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            port = mkOption {
 | 
						|
              type = types.int;
 | 
						|
              default = 9000;
 | 
						|
              description = ''
 | 
						|
                Minio listen port.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            secure = mkOption {
 | 
						|
              type = types.bool;
 | 
						|
              default = true;
 | 
						|
              description = ''
 | 
						|
                Whether to use HTTPS for Minio.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
          };
 | 
						|
        });
 | 
						|
        default = null;
 | 
						|
        description = "Configure the minio third-party integration.";
 | 
						|
      };
 | 
						|
      s3 = mkOption {
 | 
						|
        type = types.nullOr (types.submodule {
 | 
						|
          options = {
 | 
						|
            accessKeyId = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                AWS access key id.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            secretAccessKey = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                AWS access key.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            region = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                AWS S3 region.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
          };
 | 
						|
        });
 | 
						|
        default = null;
 | 
						|
        description = "Configure the s3 third-party integration.";
 | 
						|
      };
 | 
						|
      s3bucket = mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = null;
 | 
						|
        description = ''
 | 
						|
          Specify the bucket name for upload types <literal>s3</literal> and <literal>minio</literal>.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      allowPDFExport = mkOption {
 | 
						|
        type = types.bool;
 | 
						|
        default = true;
 | 
						|
        description = ''
 | 
						|
          Whether to enable PDF exports.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      imgur.clientId = mkOption {
 | 
						|
        type = types.nullOr types.str;
 | 
						|
        default = null;
 | 
						|
        description = ''
 | 
						|
          Imgur API client ID.
 | 
						|
        '';
 | 
						|
      };
 | 
						|
      azure = mkOption {
 | 
						|
        type = types.nullOr (types.submodule {
 | 
						|
          options = {
 | 
						|
            connectionString = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Azure Blob Storage connection string.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            container = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Azure Blob Storage container name.
 | 
						|
                It will be created if non-existent.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
          };
 | 
						|
        });
 | 
						|
        default = null;
 | 
						|
        description = "Configure the azure third-party integration.";
 | 
						|
      };
 | 
						|
      oauth2 = mkOption {
 | 
						|
        type = types.nullOr (types.submodule {
 | 
						|
          options = {
 | 
						|
            authorizationURL = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Specify the OAuth authorization URL.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            tokenURL = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Specify the OAuth token URL.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            clientID = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Specify the OAuth client ID.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            clientSecret = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Specify the OAuth client secret.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
          };
 | 
						|
        });
 | 
						|
        default = null;
 | 
						|
        description = "Configure the OAuth integration.";
 | 
						|
      };
 | 
						|
      facebook = mkOption {
 | 
						|
        type = types.nullOr (types.submodule {
 | 
						|
          options = {
 | 
						|
            clientID = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Facebook API client ID.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            clientSecret = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Facebook API client secret.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
          };
 | 
						|
        });
 | 
						|
        default = null;
 | 
						|
        description = "Configure the facebook third-party integration";
 | 
						|
      };
 | 
						|
      twitter = mkOption {
 | 
						|
        type = types.nullOr (types.submodule {
 | 
						|
          options = {
 | 
						|
            consumerKey = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Twitter API consumer key.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            consumerSecret = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Twitter API consumer secret.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
          };
 | 
						|
        });
 | 
						|
        default = null;
 | 
						|
        description = "Configure the Twitter third-party integration.";
 | 
						|
      };
 | 
						|
      github = mkOption {
 | 
						|
        type = types.nullOr (types.submodule {
 | 
						|
          options = {
 | 
						|
            clientID = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                GitHub API client ID.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            clientSecret = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Github API client secret.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
          };
 | 
						|
        });
 | 
						|
        default = null;
 | 
						|
        description = "Configure the GitHub third-party integration.";
 | 
						|
      };
 | 
						|
      gitlab = mkOption {
 | 
						|
        type = types.nullOr (types.submodule {
 | 
						|
          options = {
 | 
						|
            baseURL = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              default = "";
 | 
						|
              description = ''
 | 
						|
                GitLab API authentication endpoint.
 | 
						|
                Only needed for other endpoints than gitlab.com.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            clientID = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                GitLab API client ID.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            clientSecret = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                GitLab API client secret.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            scope = mkOption {
 | 
						|
              type = types.enum [ "api" "read_user" ];
 | 
						|
              default = "api";
 | 
						|
              description = ''
 | 
						|
                GitLab API requested scope.
 | 
						|
                GitLab snippet import/export requires api scope.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
          };
 | 
						|
        });
 | 
						|
        default = null;
 | 
						|
        description = "Configure the GitLab third-party integration.";
 | 
						|
      };
 | 
						|
      mattermost = mkOption {
 | 
						|
        type = types.nullOr (types.submodule {
 | 
						|
          options = {
 | 
						|
            baseURL = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Mattermost authentication endpoint.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            clientID = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Mattermost API client ID.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            clientSecret = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Mattermost API client secret.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
          };
 | 
						|
        });
 | 
						|
        default = null;
 | 
						|
        description = "Configure the Mattermost third-party integration.";
 | 
						|
      };
 | 
						|
      dropbox = mkOption {
 | 
						|
        type = types.nullOr (types.submodule {
 | 
						|
          options = {
 | 
						|
            clientID = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Dropbox API client ID.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            clientSecret = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Dropbox API client secret.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            appKey = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Dropbox app key.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
          };
 | 
						|
        });
 | 
						|
        default = null;
 | 
						|
        description = "Configure the Dropbox third-party integration.";
 | 
						|
      };
 | 
						|
      google = mkOption {
 | 
						|
        type = types.nullOr (types.submodule {
 | 
						|
          options = {
 | 
						|
            clientID = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Google API client ID.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            clientSecret = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Google API client secret.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
          };
 | 
						|
        });
 | 
						|
        default = null;
 | 
						|
        description = "Configure the Google third-party integration.";
 | 
						|
      };
 | 
						|
      ldap = mkOption {
 | 
						|
        type = types.nullOr (types.submodule {
 | 
						|
          options = {
 | 
						|
            providerName = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              default = "";
 | 
						|
              description = ''
 | 
						|
                Optional name to be displayed at login form, indicating the LDAP provider.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            url = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              example = "ldap://localhost";
 | 
						|
              description = ''
 | 
						|
                URL of LDAP server.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            bindDn = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Bind DN for LDAP access.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            bindCredentials = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              description = ''
 | 
						|
                Bind credentials for LDAP access.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            searchBase = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              example = "o=users,dc=example,dc=com";
 | 
						|
              description = ''
 | 
						|
                LDAP directory to begin search from.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            searchFilter = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              example = "(uid={{username}})";
 | 
						|
              description = ''
 | 
						|
                LDAP filter to search with.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            searchAttributes = mkOption {
 | 
						|
              type = types.listOf types.str;
 | 
						|
              example = [ "displayName" "mail" ];
 | 
						|
              description = ''
 | 
						|
                LDAP attributes to search with.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            userNameField = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              default = "";
 | 
						|
              description = ''
 | 
						|
                LDAP field which is used as the username on CodiMD.
 | 
						|
                By default <option>useridField</option> is used.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            useridField = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              example = "uid";
 | 
						|
              description = ''
 | 
						|
                LDAP field which is a unique identifier for users on CodiMD.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            tlsca = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              example = "server-cert.pem,root.pem";
 | 
						|
              description = ''
 | 
						|
                Root CA for LDAP TLS in PEM format.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
          };
 | 
						|
        });
 | 
						|
        default = null;
 | 
						|
        description = "Configure the LDAP integration.";
 | 
						|
      };
 | 
						|
      saml = mkOption {
 | 
						|
        type = types.nullOr (types.submodule {
 | 
						|
          options = {
 | 
						|
            idpSsoUrl = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              example = "https://idp.example.com/sso";
 | 
						|
              description = ''
 | 
						|
                IdP authentication endpoint.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            idpCert = mkOption {
 | 
						|
              type = types.path;
 | 
						|
              example = "/path/to/cert.pem";
 | 
						|
              description = ''
 | 
						|
                Path to IdP certificate file in PEM format.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            issuer = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              default = "";
 | 
						|
              description = ''
 | 
						|
                Optional identity of the service provider.
 | 
						|
                This defaults to the server URL.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            identifierFormat = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              default = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress";
 | 
						|
              description = ''
 | 
						|
                Optional name identifier format.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            groupAttribute = mkOption {
 | 
						|
              type = types.str;
 | 
						|
              default = "";
 | 
						|
              example = "memberOf";
 | 
						|
              description = ''
 | 
						|
                Optional attribute name for group list.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            externalGroups = mkOption {
 | 
						|
              type = types.listOf types.str;
 | 
						|
              default = [];
 | 
						|
              example = [ "Temporary-staff" "External-users" ];
 | 
						|
              description = ''
 | 
						|
                Excluded group names.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            requiredGroups = mkOption {
 | 
						|
              type = types.listOf types.str;
 | 
						|
              default = [];
 | 
						|
              example = [ "Hackmd-users" "Codimd-users" ];
 | 
						|
              description = ''
 | 
						|
                Required group names.
 | 
						|
              '';
 | 
						|
            };
 | 
						|
            attribute = {
 | 
						|
              id = mkOption {
 | 
						|
                type = types.str;
 | 
						|
                default = "";
 | 
						|
                description = ''
 | 
						|
                  Attribute map for `id'.
 | 
						|
                  Defaults to `NameID' of SAML response.
 | 
						|
                '';
 | 
						|
              };
 | 
						|
              username = mkOption {
 | 
						|
                type = types.str;
 | 
						|
                default = "";
 | 
						|
                description = ''
 | 
						|
                  Attribute map for `username'.
 | 
						|
                  Defaults to `NameID' of SAML response.
 | 
						|
                '';
 | 
						|
              };
 | 
						|
              email = mkOption {
 | 
						|
                type = types.str;
 | 
						|
                default = "";
 | 
						|
                description = ''
 | 
						|
                  Attribute map for `email'.
 | 
						|
                  Defaults to `NameID' of SAML response if
 | 
						|
                  <option>identifierFormat</option> has
 | 
						|
                  the default value.
 | 
						|
                '';
 | 
						|
              };
 | 
						|
            };
 | 
						|
          };
 | 
						|
        });
 | 
						|
        default = null;
 | 
						|
        description = "Configure the SAML integration.";
 | 
						|
      };
 | 
						|
    };
 | 
						|
  };
 | 
						|
 | 
						|
  config = mkIf cfg.enable {
 | 
						|
    assertions = [
 | 
						|
      { assertion = cfg.configuration.db == {} -> (
 | 
						|
          cfg.configuration.dbURL != "" && cfg.configuration.dbURL != null
 | 
						|
        );
 | 
						|
        message = "Database configuration for CodiMD missing."; }
 | 
						|
    ];
 | 
						|
    users.groups.codimd = {};
 | 
						|
    users.users.codimd = {
 | 
						|
      description = "CodiMD service user";
 | 
						|
      group = "codimd";
 | 
						|
      extraGroups = cfg.groups;
 | 
						|
      home = cfg.workDir;
 | 
						|
      createHome = true;
 | 
						|
    };
 | 
						|
 | 
						|
    systemd.services.codimd = {
 | 
						|
      description = "CodiMD Service";
 | 
						|
      wantedBy = [ "multi-user.target" ];
 | 
						|
      after = [ "networking.target" ];
 | 
						|
      serviceConfig = {
 | 
						|
        WorkingDirectory = cfg.workDir;
 | 
						|
        ExecStart = "${pkgs.codimd}/bin/codimd";
 | 
						|
        Environment = [
 | 
						|
          "CMD_CONFIG_FILE=${prettyJSON cfg.configuration}"
 | 
						|
          "NODE_ENV=production"
 | 
						|
        ];
 | 
						|
        Restart = "always";
 | 
						|
        User = "codimd";
 | 
						|
        PrivateTmp = true;
 | 
						|
      };
 | 
						|
    };
 | 
						|
  };
 | 
						|
}
 |