diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dba7864..dcf5564 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,14 +1,29 @@ stages: - test + - doc -image: code.ungleich.ch:5050/ungleich-public/cdist/cdist-ci:latest +image: code.ungleich.ch:5050/ungleich-public/cdist-contrib/ci-container:latest shellcheck: stage: test script: - - ./scripts/run-shellcheck.sh + - make lint manpages: stage: test script: - - ./scripts/run-manpage-checks.sh + - make check-manpages + +docs: + stage: doc + only: + - master@ungleich-public/cdist-contrib + before_script: + - eval $(ssh-agent -s) + - echo "$CD_SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - > /dev/null + - mkdir -p ~/.ssh + - echo "$CD_SSH_SERVER_HOSTKEYS" > ~/.ssh/known_hosts + - chmod 644 ~/.ssh/known_hosts + script: + - make html + - sftp fnux@staticwebhosting.ungleich.ch:public_html/cdist-contrib <<< "put -r docs/dist/html/*" diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index d2ebad0..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,3 +0,0 @@ -# cdist-contrib changes - -* 2020-04-28: New type: __find_exec (Ander Punnar) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1a0cfb3 --- /dev/null +++ b/Makefile @@ -0,0 +1,70 @@ +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo "man build only man user documentation" + @echo "html build only html user documentation" + @echo "docs build both man and html user documentation" + @echo "check-manpages check for manpage in types" + @echo "lint run shellcheck on types" + @echo "check run both type manpage checks and linting" + @echo "clean clean" + +DOCS_SRC_DIR=./docs/src +TYPEDIR=./type + +SPHINXM=make -C $(DOCS_SRC_DIR) man +SPHINXH=make -C $(DOCS_SRC_DIR) html +SPHINXC=make -C $(DOCS_SRC_DIR) clean + +################################################################################ +# Manpages +# +MAN7DSTDIR=$(DOCS_SRC_DIR)/man7 + +# Use shell / ls to get complete list - $(TYPEDIR)/*/man.rst does not work +# Using ls does not work if no file with given pattern exist, so use wildcard +MANTYPESRC=$(wildcard $(TYPEDIR)/*/man.rst) +MANTYPEPREFIX=$(subst $(TYPEDIR)/,$(MAN7DSTDIR)/cdist-type,$(MANTYPESRC)) +MANTYPES=$(subst /man.rst,.rst,$(MANTYPEPREFIX)) + +# Link manpage: do not create man.html but correct named file +$(MAN7DSTDIR)/cdist-type%.rst: $(TYPEDIR)/%/man.rst + mkdir -p $(MAN7DSTDIR) + ln -sf "../../../$^" $@ + +DOCSINDEX=$(MAN7DSTDIR)/index.rst +DOCSINDEXH=$(DOCS_SRC_DIR)/index.rst.sh + +$(DOCSINDEX): $(DOCSINDEXH) + $(DOCSINDEXH) + +# Manpages: .cdist Types +DOT_CDIST_PATH=${HOME}/.cdist +DOTMAN7DSTDIR=$(MAN7DSTDIR) +DOTTYPEDIR=$(DOT_CDIST_PATH)/type + +# Link manpage: do not create man.html but correct named file +$(DOTMAN7DSTDIR)/cdist-type%.rst: $(DOTTYPEDIR)/%/man.rst + ln -sf "$^" $@ + +man: $(MANTYPES) $(DOCSINDEX) + $(SPHINXM) + +html: $(MANTYPES) $(DOCSINDEX) + $(SPHINXH) + +docs: man html + +check-manpages: + ./scripts/run-manpage-checks.sh + +lint: + ./scripts/run-shellcheck.sh + +check: check-manpages lint + +clean: + $(SPHINXC) + rm -f docs/src/index.rst + rm -rf docs/src/man7/ + rm -rf docs/src/__pycache__/ diff --git a/README.md b/README.md index ef4b2c3..f523c3b 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,9 @@ tool with community-maitained types which are either too specific to fit/be maintained in cdist itself or were not accepted in code cdist but could still be useful. -This project does not have releases and is continously updated: see -`CHANGELOG.md` for details. +This project does not have releases and is continously updated: see git history +for change log. You will find HTML documentation at +[contrib.cdi.st](https://contrib.cdi.st). ## Using cdist-contrib @@ -32,14 +33,11 @@ And you would run [cdist][cdist] from the same directory as follows: ## Participating in the [cdist][cdist] community -Join us on [#cdist:ungleich.ch][cdistmatrix] on matrix or on -[#cdist over mattermost][cdistmattermost]. - +Join us on [#cdist:ungleich.ch][cdistmatrix] on matrix! [cdist]: https://www.cdi.st/ [cdistconfig]: https://www.cdi.st/manual/latest/cdist-configuration.html [cdistmatrix]: https://matrix.to/#/#cdist:ungleich.ch -[cdistmattermost]: https://chat.ungleich.ch/ungleich/channels/cdist ## Contributing @@ -53,3 +51,12 @@ Every type in cdist-contrib must: * Have a `man.rst` documentation page. * Pass [shellcheck](http://shellcheck.net/) without errors. + +## Other resources + +Some people/organizations are known to keep some cdist types that might be of +interest to others: + +* [cdist-evilham](https://git.sr.ht/~evilham/cdist-evilham): Evilham's cdist-types +* [cdist-recycledcloud](https://code.recycled.cloud/RecycledCloud/cdist-recycledcloud): e-Durable SA / Recycled Cloud public types +* [cdist-ungleich](https://code.ungleich.ch/ungleich-public/cdist-ungleich): ungleich public types diff --git a/docs/src/Makefile b/docs/src/Makefile new file mode 100644 index 0000000..2e9d6ce --- /dev/null +++ b/docs/src/Makefile @@ -0,0 +1,235 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +PAPER ?= +BUILDDIR ?= ../dist +# for cache, etc. +_BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) + $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don\'t have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(_BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " applehelp to make an Apple Help Book" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " epub3 to make an epub3" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + @echo " coverage to run coverage check of the documentation (if enabled)" + @echo " dummy to check syntax errors of document sources" + +.PHONY: clean +clean: + rm -rf $(BUILDDIR)/* + rm -rf $(_BUILDDIR)/* + +.PHONY: html +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +.PHONY: dirhtml +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +.PHONY: singlehtml +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +.PHONY: pickle +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +.PHONY: json +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +.PHONY: htmlhelp +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +.PHONY: qthelp +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/cdist-docs.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/cdist-docs.qhc" + +.PHONY: applehelp +applehelp: + $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp + @echo + @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." + @echo "N.B. You won't be able to view it unless you put it in" \ + "~/Library/Documentation/Help or install it in your application" \ + "bundle." + +.PHONY: devhelp +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/cdist-docs" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/cdist-docs" + @echo "# devhelp" + +.PHONY: epub +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +.PHONY: epub3 +epub3: + $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 + @echo + @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." + +.PHONY: latex +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +.PHONY: latexpdf +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: latexpdfja +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +.PHONY: text +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +.PHONY: man +man: + $(SPHINXBUILD) -b cman $(ALLSPHINXOPTS) $(BUILDDIR)/man + mkdir -p $(BUILDDIR)/man/man7 + mv -f $(BUILDDIR)/man/*.7 $(BUILDDIR)/man/man7/ + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +.PHONY: texinfo +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +.PHONY: info +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +.PHONY: gettext +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +.PHONY: changes +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +.PHONY: linkcheck +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +.PHONY: doctest +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +.PHONY: coverage +coverage: + $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage + @echo "Testing of coverage in the sources finished, look at the " \ + "results in $(BUILDDIR)/coverage/python.txt." + +.PHONY: xml +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +.PHONY: pseudoxml +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." + +.PHONY: dummy +dummy: + $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy + @echo + @echo "Build finished. Dummy builder generates no files." diff --git a/docs/src/conf.py b/docs/src/conf.py new file mode 100644 index 0000000..19b2dfd --- /dev/null +++ b/docs/src/conf.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 + +import sys +import os +import sphinx_rtd_theme + +from datetime import date + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# sys.path.insert(0, os.path.abspath('.')) +sys.path.insert(0, os.path.abspath(os.path.join( + os.path.dirname(os.path.realpath(__file__)), "..", ".."))) + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'docs.src.manpage', + 'sphinx.ext.extlinks', +] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +source_suffix = ['.rst'] + +# The encoding of source files. +# source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = 'cdist-contrib' +copyright = 'cdist-contrib contributors' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. + +version = str(date.today()) +release = os.popen('git rev-parse HEAD').read() + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'sphinx_rtd_theme' +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +# Output file base name for HTML help builder. +htmlhelp_basename = 'cdistcontribdoc' + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +root_mandir = os.path.dirname(os.path.realpath(__file__)) +mandirs = [] +for mansubdir in ('man7',): + mandirs.append((os.path.join(root_mandir, mansubdir), mansubdir[-1])) +man_pages = [] +for mandir, section in mandirs: + for root, dirs, files in os.walk(mandir): + for fname in files: + froot, fext = os.path.splitext(fname) + if fext == '.rst': + man_page = (os.path.join('man' + str(section), froot), + froot, '', [], section) + man_pages.append(man_page) + +# man_pages = [ +# ('cdist-type', 'cdist-type', 'cdist-type documentation', +# [author], 1), +# ('man7/cdist-type__file', 'cdist-type__file', +# '', [], 1), +# ('cdist-type__directory', 'cdist-type__directory', +# 'cdist-type__directory documentation', [author], 1), +# ] + +# If true, show URL addresses after external links. +# man_show_urls = False diff --git a/docs/src/index.rst.sh b/docs/src/index.rst.sh new file mode 100755 index 0000000..babc1d9 --- /dev/null +++ b/docs/src/index.rst.sh @@ -0,0 +1,40 @@ +#!/bin/sh + +__cdist_pwd="$(pwd -P)" +__cdist_mydir="${0%/*}"; +__cdist_abs_mydir="$(cd "$__cdist_mydir" && pwd -P)" +__cdist_myname=${0##*/}; +__cdist_abs_myname="$__cdist_abs_mydir/$__cdist_myname" + +filename="${__cdist_myname%.sh}" +dest="$__cdist_abs_mydir/$filename" + +if ! command -v pandoc > /dev/null; then + echo "Pandoc is required to generate HTML index from README." >&2 + exit 1 +fi + +cd "$__cdist_abs_mydir" + +exec > "$dest" + +pandoc -f markdown -t rst ../../README.md + +cat << EOF + +.. toctree:: + :hidden: + +EOF + +# If there is no such file then ls prints error to stderr, +# so redirect stderr to /dev/null. +for type in $(ls man7/cdist-type__*.rst 2>/dev/null | LC_ALL=C sort); do + no_dir="${type#man7/}"; + no_type="${no_dir#cdist-type}"; + name="${no_type%.rst}"; + manref="${no_dir%.rst}" + man="${manref}(7)" + + echo " $name" "" +done diff --git a/docs/src/manpage.py b/docs/src/manpage.py new file mode 100644 index 0000000..1f8ac4f --- /dev/null +++ b/docs/src/manpage.py @@ -0,0 +1,87 @@ +import sphinx.builders.manpage +import sphinx.writers.manpage +from docutils.frontend import OptionParser +from sphinx.util.console import bold, darkgreen +from six import string_types +from docutils.io import FileOutput +from os import path +from sphinx.util.nodes import inline_all_toctrees +from sphinx import addnodes +from sphinx.util import logging + +""" + Extension based on sphinx builtin manpage. + It does not write its own .SH NAME based on config, + but leaves everything to actual reStructuredText file content. +""" + + +logger = logging.getLogger(__name__) + + +class ManualPageTranslator(sphinx.writers.manpage.ManualPageTranslator): + + def header(self): + tmpl = (".TH \"%(title_upper)s\" \"%(manual_section)s\"" + " \"%(date)s\" \"%(version)s\" \"%(manual_group)s\"\n") + return tmpl % self._docinfo + + +class ManualPageWriter(sphinx.writers.manpage.ManualPageWriter): + + def __init__(self, builder): + super().__init__(builder) + self.translator_class = ( + self.builder.get_translator_class() or ManualPageTranslator) + + +class ManualPageBuilder(sphinx.builders.manpage.ManualPageBuilder): + + name = 'cman' + default_translator_class = ManualPageTranslator + + def write(self, *ignored): + docwriter = ManualPageWriter(self) + docsettings = OptionParser( + defaults=self.env.settings, + components=(docwriter,), + read_config_files=True).get_default_values() + + logger.info(bold('writing... '), nonl=True) + + for info in self.config.man_pages: + docname, name, description, authors, section = info + if isinstance(authors, string_types): + if authors: + authors = [authors] + else: + authors = [] + + targetname = '%s.%s' % (name, section) + logger.info(darkgreen(targetname) + ' { ', nonl=True) + destination = FileOutput( + destination_path=path.join(self.outdir, targetname), + encoding='utf-8') + + tree = self.env.get_doctree(docname) + docnames = set() + largetree = inline_all_toctrees(self, docnames, docname, tree, + darkgreen, [docname]) + logger.info('} ', nonl=True) + self.env.resolve_references(largetree, docname, self) + # remove pending_xref nodes + for pendingnode in largetree.traverse(addnodes.pending_xref): + pendingnode.replace_self(pendingnode.children) + + largetree.settings = docsettings + largetree.settings.title = name + largetree.settings.subtitle = description + largetree.settings.authors = authors + largetree.settings.section = section + + docwriter.write(largetree, destination) + logger.info("") + + +def setup(app): + app.add_builder(ManualPageBuilder) diff --git a/scripts/ci-container/Dockerfile b/scripts/ci-container/Dockerfile new file mode 100644 index 0000000..9900322 --- /dev/null +++ b/scripts/ci-container/Dockerfile @@ -0,0 +1,7 @@ +# This image is used in the cdist-contrib CI for linting and generating the +# documentation. +FROM fedora:latest +MAINTAINER Timothée Floure + +RUN dnf install -y git findutils make python3-sphinx python3-sphinx_rtd_theme \ + ShellCheck openssh-clients pandoc diff --git a/scripts/run-shellcheck.sh b/scripts/run-shellcheck.sh index 769f853..d6c2db6 100755 --- a/scripts/run-shellcheck.sh +++ b/scripts/run-shellcheck.sh @@ -1,21 +1,29 @@ -#!/bin/sh +#!/bin/sh -eu -SHELLCHECKCMD="shellcheck -s sh -f gcc -x" +SHELLCHECKCMD='shellcheck -s sh -f gcc -x' # Skip SC2154 for variables starting with __ since such variables are cdist # environment variables. SHELLCHECK_SKIP=': __.*is referenced but not assigned.*\[SC2154\]' -SHELLCHECKTMP=".shellcheck.tmp" +SHELLCHECKTMP='.shellcheck.tmp' # Move to top-level cdist-contrib directory. -cd $(dirname $0)/.. +cd "$(dirname $0)"/.. -check () { - find type/ -type f $1 $2 -exec ${SHELLCHECKCMD} {} + | grep -v "${SHELLCHECK_SKIP}" > "${SHELLCHECKTMP}" - test ! -s "${SHELLCHECKTMP}" || { cat "${SHELLCHECKTMP}"; exit 1; } +check() { + find type/ -type f "$@" -exec ${SHELLCHECKCMD} {} + \ + | grep -v "${SHELLCHECK_SKIP}" >>"${SHELLCHECKTMP}" || true } -check -path "*/explorer/*" -check -path "*/files/*" +rm -f "${SHELLCHECKTMP}" + +check -path '*/explorer/*' +check -path '*/files/*' -name '*.sh' check -name manifest check -name gencode-local check -name gencode-remote + +if test -s "${SHELLCHECKTMP}" +then + cat "${SHELLCHECKTMP}" >&2 + exit 1 +fi diff --git a/type/__bird_bgp/files/template.sh b/type/__bird_bgp/files/template.sh new file mode 100755 index 0000000..4d8f297 --- /dev/null +++ b/type/__bird_bgp/files/template.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# Template to generate a bgp protocol configuration file for bird(1). +# Required non-empty variables: +# __object_id, local_{ip,as}, neighbor_{ip,as} +# +# Required defined variables: +# description, password, ipv{4,6}_{import,export} + +# Header +echo "protocol bgp ${__object_id:?} {" + +# Optional description +[ -n "${description?}" ] && printf "\tdescription \"%s\";\n" "${description?}" + +# Mandatory session information +cat << EOF + local ${local_ip?} as ${local_as:?}; + neighbor ${neighbor_ip:?} as ${neighbor_as:?}; +EOF + +# Direct connection ? +[ -n "${direct?}" ] && printf "\tdirect;\n" + +# Password-protected session ? +[ -n "${password?}" ] && printf "\tpassword \"%s\";\n" "${password?}" + +if [ -n "${ipv4_import?}" ] || [ -n "${ipv4_export?}" ] || "${ipv4_extended_next_hop?}"; +then + printf "\tipv4 {\n" + [ -n "${ipv4_import?}" ] && printf "\t\timport %s;\n" "${ipv4_import:?}" + [ -n "${ipv4_export?}" ] && printf "\t\texport %s;\n" "${ipv4_export:?}" + [ -n "${ipv4_extended_next_hop?}" ] && printf "\t\textended next hop;\n" + printf "\t};\n" +fi +if [ -n "${ipv6_import?}" ] || [ -n "${ipv6_export?}" ] || "${ipv6_extended_next_hop?}"; +then + printf "\tipv6 {\n" + [ -n "${ipv6_import?}" ] && printf "\t\timport %s;\n" "${ipv6_import:?}" + [ -n "${ipv6_export?}" ] && printf "\t\texport %s;\n" "${ipv6_export:?}" + [ -n "${ipv6_extended_next_hop?}" ] && printf "\t\textended next hop;\n" + printf "\t};\n" +fi + +# Header close +echo "}" diff --git a/type/__bird_bgp/man.rst b/type/__bird_bgp/man.rst new file mode 100644 index 0000000..7b55ab5 --- /dev/null +++ b/type/__bird_bgp/man.rst @@ -0,0 +1,105 @@ +cdist-type__bird_bgp(7) +======================= + +NAME +---- +cdist-type__bird_bgp - configure an instance of the BGP protocol. + + +DESCRIPTION +----------- +This type writes the configuration for an instance of the BGP protocol to be +ran by the bird internet routing daemon. It **expects** to depend on the +`cdist-type__bird_core(7)` type. + + +REQUIRED PARAMETERS +------------------- +local-as + The number for the AS in which the daemon is running. + +neighbor-as + The number of the AS with which we are peering. + +neighbor-ip + The IP address of the peer we are opening a session with. + + +OPTIONAL PARAMETERS +------------------- +description + An instance desciption to be printed when `birdc show protocols` is called. + +local-ip + The IP address used as a source address for the BGP session. + +password + A password for the BGP session. + +ipv4-import + A string suitable for the bird `import` directive. Usually `all`, `none` or + a filter definition. + +ipv4-export + See ipv4-import. + +ipv4-extended-next-hop + Allow IPv6 next hop in IPv4 NLRI. + +ipv6-import + See ipv4-import. + +ipv6-export + See ipv4-import. + +ipv6-extended-next-hop + Allow IPv4 next hop in IPv6 NLRI. + + +BOOLEAN PARAMETERS +------------------ +direct + Specify that the two routers are directly connected. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Setup bird and open a BGP session. + __bird_core --router-id 198.51.100.4 + + require='__bird_core' __bird_bgp bgp4 \ + --description "a test IPv4 BGP instance" \ + --ipv4-export all \ + --ipv4-import all \ + --ipv6-export none \ + --ipv6-import none \ + --local-as 1234 \ + --local-ip 198.51.100.4 \ + --neighbor-as 4321 \ + --neighbor-ip 198.51.100.3 \ + --password hunter01 + + +SEE ALSO +-------- +cdist-type__bird_core(7) +cdist-type__bird_filter(7) +cdist-type__bird_kernel(7) +cdist-type__bird_ospf(7) +cdist-type__bird_static(7) + + +AUTHORS +------- +Joachim Desroches + + +COPYING +------- +Copyright \(C) 2021 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__bird_bgp/manifest b/type/__bird_bgp/manifest new file mode 100755 index 0000000..7525bb5 --- /dev/null +++ b/type/__bird_bgp/manifest @@ -0,0 +1,122 @@ +#!/bin/sh -e +# +# 2021 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + + +os=$(cat "${__global:?}/explorer/os") + +case "$os" in + "alpine"|"debian"|"ubuntu") + confdir="/etc/bird.d" + ;; + *) + printf "Your operating system (%s) is currently not supported by __bird_bgp\n" "$os" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +# Required parameters +local_as="$(cat "${__object:?}"/parameter/local-as)" +export local_as + +neighbor_as="$(cat "${__object:?}"/parameter/neighbor-as)" +export neighbor_as + +neighbor_ip="$(cat "${__object:?}"/parameter/neighbor-ip)" +export neighbor_ip + +# Optional parameters +description= +if [ -f "${__object:?}"/parameter/description ]; +then + description="$(cat "${__object:?}"/parameter/description)" +fi +export description + +direct= +if [ -f "${__object:?}"/parameter/direct ]; +then + direct="true" +fi +export direct + +ipv4_extended_next_hop= +if [ -f "${__object:?}"/parameter/ipv4-extended-next-hop ]; +then + ipv4_extended_next_hop="true" +fi +export ipv4_extended_next_hop + +ipv6_extended_next_hop= +if [ -f "${__object:?}"/parameter/ipv6-extended-next-hop ]; +then + ipv6_extended_next_hop="true" +fi +export ipv6_extended_next_hop + +local_ip= +if [ -f "${__object:?}"/parameter/local-ip ]; +then + local_ip="$(cat "${__object:?}"/parameter/local-ip)" +fi +export local_ip + +password= +if [ -f "${__object:?}"/parameter/password ]; +then + password="$(cat "${__object:?}"/parameter/password)" +fi +export password + +ipv4_import= +if [ -f "${__object:?}"/parameter/ipv4-import ]; +then + ipv4_import="$(cat "${__object:?}"/parameter/ipv4-import)" +fi +export ipv4_import + +ipv4_export= +if [ -f "${__object:?}"/parameter/ipv4-export ]; +then + ipv4_export="$(cat "${__object:?}"/parameter/ipv4-export)" +fi +export ipv4_export + +ipv6_import= +if [ -f "${__object:?}"/parameter/ipv6-import ]; +then + ipv6_import="$(cat "${__object:?}"/parameter/ipv6-import)" +fi +export ipv6_import + +ipv6_export= +if [ -f "${__object:?}"/parameter/ipv6-export ]; +then + ipv6_export="$(cat "${__object:?}"/parameter/ipv6-export)" +fi +export ipv6_export + +# Run template +"${__type:?}"/files/template.sh > "${__files:?}/bgp-${__object_id:?}.conf" + +# Install resulting configuration +__file "${confdir:?}"/bgp-"${__object_id:?}".conf \ + --mode 0640 --owner root --group bird \ + --source "${__files:?}/bgp-${__object_id:?}.conf" diff --git a/type/__bird_bgp/parameter/boolean b/type/__bird_bgp/parameter/boolean new file mode 100644 index 0000000..1c34b58 --- /dev/null +++ b/type/__bird_bgp/parameter/boolean @@ -0,0 +1,3 @@ +direct +ipv4-extended-next-hop +ipv6-extended-next-hop diff --git a/type/__bird_bgp/parameter/optional b/type/__bird_bgp/parameter/optional new file mode 100644 index 0000000..b9624a9 --- /dev/null +++ b/type/__bird_bgp/parameter/optional @@ -0,0 +1,7 @@ +description +ipv4-export +ipv4-import +ipv6-export +ipv6-import +local-ip +password diff --git a/type/__bird_bgp/parameter/required b/type/__bird_bgp/parameter/required new file mode 100644 index 0000000..9b82660 --- /dev/null +++ b/type/__bird_bgp/parameter/required @@ -0,0 +1,3 @@ +local-as +neighbor-as +neighbor-ip diff --git a/type/__bird_core/man.rst b/type/__bird_core/man.rst new file mode 100644 index 0000000..7bf3dc1 --- /dev/null +++ b/type/__bird_core/man.rst @@ -0,0 +1,65 @@ +cdist-type__bird-core(7) +======================== + +NAME +---- +cdist-type__bird-core - setup a skeleton bird configuration. + + +DESCRIPTION +----------- +The `bird`_ daemon is an internet routing daemon, running protocols such as +OSPF and BGP. This type creates a skeleton configuration file suitable for +running a no-op bird. It is then intended to be combined - and depended on - by +types specific to the instances of the various protocols that bird should run. + +.. _bird: https://bird.network.cz/ + +OPTIONAL PARAMETERS +------------------- +router-id + This parameter follows the format of an IPv4 address, and will be used by + bird as its router id. See `the documentation for router id`_. + +.. _the documentation for router id: https://bird.network.cz/?get_doc&v=20&f=bird-3.html#opt-router-id + +log-params + + This parameter expects a string suitable to follow the `log` bird + configuration key. If this parameter is not include, the value `syslog all` + is used. See `the documentation for log`_. + +.. _the documentation for log: https://bird.network.cz/?get_doc&v=20&f=bird-3.html#opt-log + + +EXAMPLES +-------- + +.. code-block:: sh + + __bird-core --router-id 198.51.100.4 + + require='__bird-core' __bird_bgp <...> + require='__bird-core' __bird_ospf <...> + + +SEE ALSO +-------- +cdist-type__bird_bgp(7) +cdist-type__bird_filter(7) +cdist-type__bird_kernel(7) +cdist-type__bird_ospf(7) +cdist-type__bird_static(7) + + +AUTHORS +------- +Joachim Desroches + + +COPYING +------- +Copyright \(C) 2021 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__bird_core/manifest b/type/__bird_core/manifest new file mode 100755 index 0000000..63b58d3 --- /dev/null +++ b/type/__bird_core/manifest @@ -0,0 +1,72 @@ +#!/bin/sh -e +# +# 2021 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + + +os=$(cat "${__global:?}/explorer/os") + +package= +conffile= +confdir= +case "$os" in + "alpine") + package=bird + conffile=/etc/bird.conf + confdir=/etc/bird.d + ;; + *) + printf "Your operating system (%s) is currently not supported by __bird_core\n" "$os" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +router_id= +if [ -f "${__object:?}/parameter/router-id" ]; +then + router_id="router id $(cat "${__object:?}"/parameter/router-id);" +fi + +log_params="syslog all" +if [ -f "${__object:?}/parameter/log-params" ]; +then + log_params="$(cat "${__object:?}"/parameter/log-params)" +fi + +__package "$package" + +export require="__package/$package" +__directory "$confdir" +__file "$conffile" \ + --mode 0640 --owner root --group bird \ + --source - << EOF +# $conffile - bird(1) configuration file. +# Managed by cdist. Do not edit by hand. + +${router_id} +log ${log_params}; + +# Always include this "protocol": all it does is expose the available +# interfaces to bird. +protocol device { + description "Obtain a list of device interfaces."; +} + +include "$confdir/*.conf"; +EOF diff --git a/type/__bird_core/parameter/optional b/type/__bird_core/parameter/optional new file mode 100644 index 0000000..40d74bf --- /dev/null +++ b/type/__bird_core/parameter/optional @@ -0,0 +1 @@ +log-params diff --git a/type/__bird_core/parameter/required b/type/__bird_core/parameter/required new file mode 100644 index 0000000..8fb6ae6 --- /dev/null +++ b/type/__bird_core/parameter/required @@ -0,0 +1 @@ +router-id diff --git a/type/__root_mail_dma/singleton b/type/__bird_core/singleton similarity index 100% rename from type/__root_mail_dma/singleton rename to type/__bird_core/singleton diff --git a/type/__bird_filter/man.rst b/type/__bird_filter/man.rst new file mode 100644 index 0000000..a1ebf0b --- /dev/null +++ b/type/__bird_filter/man.rst @@ -0,0 +1,63 @@ +cdist-type__bird_filter(7) +========================== + +NAME +---- +cdist-type__bird_filter - Create a named filter to use in configuring bird. + + +DESCRIPTION +----------- +This type writes a configuration file defining a filter named `__object_id` for +the bird internet routing daemon. It is guaranteed that all filters defined +through this type will be loaded before any other protocol defined using the +cdist __bird_xxx types, except functions. However, note that if two filters +have a dependency, they will be loaded in alphabetical order, so some care may +need to be taken in the naming. + +This type takes it's input through stdin, expecting valid filter statements as +per the bird configuration file syntax. The standard input will be printed out +between a `filter __object_id {\n ... \n}`, so only the inner statements are +needed. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Setup bird, a filter and open a BGP session. + __bird_core --router-id 198.51.100.4 + + require='__bird_core' __bird_filter bgp_export <<- EOF + if (source = RTS_DEVICE) then accept; + reject; + EOF + + require='__bird_core' __bird_bgp bgp4 \ + --description "a test IPv4 BGP instance" \ + --ipv4-export "filter bgp_export" \ + --[...] + + +SEE ALSO +-------- +cdist-type__bird_core(7) +cdist-type__bird_bgp(7) +cdist-type__bird_function(7) +cdist-type__bird_kernel(7) +cdist-type__bird_ospf(7) +cdist-type__bird_static(7) + + +AUTHORS +------- +Joachim Desroches + + +COPYING +------- +Copyright \(C) 2021 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__bird_filter/manifest b/type/__bird_filter/manifest new file mode 100755 index 0000000..9579598 --- /dev/null +++ b/type/__bird_filter/manifest @@ -0,0 +1,44 @@ +#!/bin/sh -e +# +# 2021 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + + +os=$(cat "${__global:?}/explorer/os") + +case "$os" in +'alpine'|'debian'|'ubuntu') + confdir=/etc/bird.d + ;; +*) + printf "Your operating system (%s) is currently not supported by __bird_filter\n" "$os" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +# Filters start with 1 because bird loads the config in alphanumerical order +# and we need them to be defined to be used in the rest of the stuff, but after +# functions. +__file "$confdir/1-filter-${__object_id:?}.conf" \ + --owner root --group bird --mode 0640 \ + --source - << EOF +filter ${__object_id:?} { +$(cat "${__object:?}"/stdin) +} +EOF diff --git a/type/__bird_function/man.rst b/type/__bird_function/man.rst new file mode 100644 index 0000000..b5488ec --- /dev/null +++ b/type/__bird_function/man.rst @@ -0,0 +1,58 @@ +cdist-type__bird_function(7) +============================ + +NAME +---- +cdist-type__bird_function - Create a named function to use in configuring bird. + + +DESCRIPTION +----------- + +This type writes a configuration file for the bird internet routing daemon. It +is guaranteed that all functions defined through this type will be loaded +before any other protocol defined using the cdist __bird_xxx types. However, +note that if two functions have a dependency, they will be loaded in +alphabetical order, so some care may need to be taken in the naming. + +This type takes it's input through stdin, expecting a valid function definition +as per the bird configuration file syntax. + +EXAMPLES +-------- + +.. code-block:: sh + + # Setup bird, a function and open a BGP session. + __bird_core --router-id 198.51.100.4 + + require='__bird_core' __bird_function is_device <<- EOF + function is_device (enum source) + { + if (source = RTS_DEVICE) then return true; + return false; + } + EOF + + +SEE ALSO +-------- +cdist-type__bird_core(7) +cdist-type__bird_bgp(7) +cdist-type__bird_filter(7) +cdist-type__bird_kernel(7) +cdist-type__bird_ospf(7) +cdist-type__bird_static(7) + + +AUTHORS +------- +Joachim Desroches + + +COPYING +------- +Copyright \(C) 2021 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__bird_function/manifest b/type/__bird_function/manifest new file mode 100755 index 0000000..9a93f35 --- /dev/null +++ b/type/__bird_function/manifest @@ -0,0 +1,41 @@ +#!/bin/sh -e +# +# 2021 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + + +os=$(cat "${__global:?}/explorer/os") + +case "$os" in +'alpine'|'debian'|'ubuntu') + confdir=/etc/bird.d + ;; +*) + printf "Your operating system (%s) is currently not supported by __bird_filter\n" "$os" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +# Functions start with 0 because bird loads the config in alphanumerical order +# and we need them to be defined to be used in the rest of the stuff. +__file "$confdir/0-function-${__object_id:?}.conf" \ + --owner root --group bird --mode 0640 \ + --source - << EOF +$(cat "${__object:?}"/stdin) +EOF diff --git a/type/__bird_kernel/man.rst b/type/__bird_kernel/man.rst new file mode 100644 index 0000000..34f1c49 --- /dev/null +++ b/type/__bird_kernel/man.rst @@ -0,0 +1,73 @@ +cdist-type__bird_kernel(7) +========================== + +NAME +---- +cdist-type__bird_kernel - configure syncing of routes with the kernel. + + +DESCRIPTION +----------- + +This type writes the configuration for an instance of the kernel protocol to be +ran by the bird internet routing daemon. It **expects** to depend on the +`cdist-type__bird_core(7)` type. + +OPTIONAL PARAMETERS +------------------- +description + An instance desciption to be printed when `birdc show protocols` is called. + +persist + Instruct bird to leave routes in kernel table after exiting. See the bird + `persist` keyword. + +learn + Learn routes added externally to the kernel routing table. See the bird + `learn` keyword. + +channel + The channel to connect the protocol to. Usually `ipv4` or `ipv6`. + +import + A string suitable for the bird `import` directive. Usually `all`, `none` or + a filter definition. + +export + See import. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Setup bird and open a BGP session. + __bird_core --router-id 198.51.100.4 + + require='__bird_core' __bird_kernel k4 \ + --learn --persist --channel ipv4 \ + --import all \ + --export all + + +SEE ALSO +-------- +cdist-type__bird_bgp(7) +cdist-type__bird_core(7) +cdist-type__bird_filter(7) +cdist-type__bird_ospf(7) +cdist-type__bird_static(7) + + +AUTHORS +------- +Joachim Desroches + + +COPYING +------- +Copyright \(C) 2021 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__bird_kernel/manifest b/type/__bird_kernel/manifest new file mode 100755 index 0000000..c5d2eac --- /dev/null +++ b/type/__bird_kernel/manifest @@ -0,0 +1,83 @@ +#!/bin/sh -e +# +# 2021 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + + +os=$(cat "${__global:?}/explorer/os") + +case "$os" in + "alpine"|"debian"|"ubuntu") + confdir="/etc/bird.d" + ;; + *) + printf "Your operating system (%s) is currently not supported by __bird_kernel\n" "$os" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +# Required parameters +channel="$(cat "${__object:?}/parameter/channel")" + +# Boolean switches +persist= +if [ -f "${__object:?}"/parameter/persist ]; +then + persist=true +fi + +learn= +if [ -f "${__object:?}"/parameter/learn ]; +then + learn=true +fi + +# Optional parameters +description= +if [ -f "${__object:?}"/parameter/description ]; +then + description="$(cat "${__object:?}/parameter/description")" +fi + +import= +if [ -f "${__object:?}"/parameter/import ]; +then + import="$(cat "${__object:?}/parameter/import")" +fi + +_export= +if [ -f "${__object:?}"/parameter/export ]; +then + _export="$(cat "${__object:?}/parameter/export")" +fi + +# Install resulting configuration +__file "${confdir:?}"/kernel-"${__object_id:?}".conf \ + --mode 0640 --owner root --group bird \ + --source - << EOF +protocol kernel ${__object_id:?} { +$([ -n "${description?}" ] && printf "\tdescription \"%s\";\n" "${description?}") +$([ -n "${persist?}" ] && printf "\tpersist;\n") +$([ -n "${learn?}" ] && printf "\tlearn;\n") + ${channel:?} { + import ${import:?}; + export ${_export:?}; + }; +} +EOF diff --git a/type/__bird_kernel/parameter/boolean b/type/__bird_kernel/parameter/boolean new file mode 100644 index 0000000..6499685 --- /dev/null +++ b/type/__bird_kernel/parameter/boolean @@ -0,0 +1,2 @@ +learn +persist diff --git a/type/__bird_kernel/parameter/optional b/type/__bird_kernel/parameter/optional new file mode 100644 index 0000000..e1b39b0 --- /dev/null +++ b/type/__bird_kernel/parameter/optional @@ -0,0 +1 @@ +description diff --git a/type/__bird_kernel/parameter/required b/type/__bird_kernel/parameter/required new file mode 100644 index 0000000..a87a501 --- /dev/null +++ b/type/__bird_kernel/parameter/required @@ -0,0 +1,3 @@ +channel +import +export diff --git a/type/__bird_ospf/man.rst b/type/__bird_ospf/man.rst new file mode 100644 index 0000000..66c2e4a --- /dev/null +++ b/type/__bird_ospf/man.rst @@ -0,0 +1,63 @@ +cdist-type__bird-ospf(7) +======================== + +NAME +---- +cdist-type__bird-ospf - Configure an instance of the OSPF protocol + + +DESCRIPTION +----------- + +This type is an *extremely rudimentary* method to configure a simple OSPF +protocol instance for bird, the internet routing daemon. Even this manpage is +pretty crude and will be fixed and expanded. + +REQUIRED PARAMETERS +------------------- +channel + The channel the protocol should connect to. Usually `ipv4` or `ipv6`. + +import + The keyword or filter to decide what to import in the above channel. + +export + The keyword or filter to decide what to export in the above channel. + +OPTIONAL PARAMETERS +------------------- +description + A description given with `show protocol all` + +instance-id + An OSPF instance ID, allowing several OSPF instances to run on the same + links. + +extra-area-configuration + Configuration string added to the `area` section of the OSPF configuration. + +OPTIONAL MULTIPLE PARAMETERS +---------------------------- + +stubnet + Add an optionless stubnet definition to the configuration. + +interface + An interface to include in OSPF area 0. Is required unless + extra-area-configuration is set. + +SEE ALSO +-------- +cdist-type__bird_core(7) + +AUTHORS +------- +Joachim Desroches + + +COPYING +------- +Copyright \(C) 2021 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__bird_ospf/manifest b/type/__bird_ospf/manifest new file mode 100755 index 0000000..68d9c16 --- /dev/null +++ b/type/__bird_ospf/manifest @@ -0,0 +1,81 @@ +#!/bin/sh -e +# +# 2021 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + + +os=$(cat "${__global:?}/explorer/os") + +case "$os" in +'alpine'|'debian'|'ubuntu') + confdir='/etc/bird.d' +;; +*) + printf "Your operating system (%s) is currently not supported by this __bird_ospf\n" "$os" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 +;; +esac + +description= +if [ -f "${__object:?}/parameter/description" ]; +then + description="$(cat "${__object:?}/parameter/description")" +fi + +instance_id= +if [ -f "${__object:?}/parameter/instance-id" ]; +then + instance_id="$(cat "${__object:?}/parameter/instance-id")" +fi + +extra_area_configuration= +if [ -f "${__object:?}/parameter/extra-area-configuration" ]; +then + extra_area_configuration="$(cat "${__object:?}/parameter/extra-area-configuration")" + + if [ "$extra_area_configuration" = "-" ]; then + extra_area_configuration=$(cat "$__object/stdin") + fi +fi + +if [ ! -f "${__object:?}/parameter/interface" ] && [ -z "$extra_area_configuration" ]; then + echo "Either --interface or --extra-area-configuration must be set." >&2 + exit 1 +fi + +__file "${confdir:?}/ospf-${__object_id:?}.conf" \ + --mode 0640 --owner root --group bird \ + --source - << EOF +protocol ospf v3 ${__object_id:?} { +$([ -n "${description?}" ] && printf "\tdescription \"%s\";\n" "${description?}") +$([ -n "${instance_id?}" ] && printf "\tinstance id %s;\n" "${instance_id?}") + + $(cat "${__object:?}/parameter/channel") { + import $(cat "${__object:?}/parameter/import"); + export $(cat "${__object:?}/parameter/export"); + }; + + area 0 { +$(sed -e 's/^/\t\tinterface "/' -e 's/$/";/' "${__object:?}/parameter/interface") +$(sed -e 's/^/\t\tsubnet /' -e 's/$/;/' "${__object:?}/parameter/subnet") + + $extra_area_configuration + }; +} +EOF diff --git a/type/__bird_ospf/parameter/optional b/type/__bird_ospf/parameter/optional new file mode 100644 index 0000000..880f228 --- /dev/null +++ b/type/__bird_ospf/parameter/optional @@ -0,0 +1,3 @@ +description +instance-id +extra-area-configuration diff --git a/type/__bird_ospf/parameter/optional_multiple b/type/__bird_ospf/parameter/optional_multiple new file mode 100644 index 0000000..8e5902d --- /dev/null +++ b/type/__bird_ospf/parameter/optional_multiple @@ -0,0 +1,2 @@ +stubnet +interface diff --git a/type/__bird_ospf/parameter/required b/type/__bird_ospf/parameter/required new file mode 100644 index 0000000..a87a501 --- /dev/null +++ b/type/__bird_ospf/parameter/required @@ -0,0 +1,3 @@ +channel +import +export diff --git a/type/__bird_radv/man.rst b/type/__bird_radv/man.rst new file mode 100644 index 0000000..27362aa --- /dev/null +++ b/type/__bird_radv/man.rst @@ -0,0 +1,83 @@ +cdist-type__bird_radv(7) +======================== + +NAME +---- +cdist-type__bird_radv - Configure the Bird Internet Router Daemon to send RAdvs. + + +DESCRIPTION +----------- + +The Bird Internet Router Daemon knows about a bunch of internet routing +protocols. In particular, it can send Router Advertisements to help +autoconfigure IPv6 hosts, this type is a rudimentary implementation to generate +configuration for Bird to do so. + + +REQUIRED PARAMETERS +------------------- +interface + The interfaces to activate the protocol on. RAs will be sent using the + prefixes configured on these interfaces. + +OPTIONAL PARAMETERS +------------------- +mtu + An optional MTU setting to include in the router advertisements. + +default-preference + This option specifies the Default Router Preference value to advertise to + hosts. Default: medium. + +route-preference + This option specifies the default value of advertised route preference for + specific routes. Default: medium. + +default-lifetime + This option specifies the time (in seconds) how long (since the receipt of RA) + hosts may use the router as a default router. 0 means do not use as a default + router. Default: 3. + +OPTIONAL MULTIPLE PARAMETERS +---------------------------- +route + Routes to be added to the RA for hosts. + +ns + Recursive DNS servers given to the hosts through RAs. + +dnssl + Search domain to be given to the hosts through RAs. + + +EXAMPLES +-------- + +.. code-block:: sh + + __bird_radv datacenter \ + --interface eth1 \ + --mtu 9000 \ + --route ::/0 \ + --ns 2001:DB8:cafe::4 \ + --ns 2001:DB8:cafe::14 \ + --dnssl "example.com" + + +SEE ALSO +-------- +`__bird_core(7)` + + +AUTHORS +------- +Joachim Desroches + + +COPYING +------- +Copyright \(C) 2021 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__bird_radv/manifest b/type/__bird_radv/manifest new file mode 100755 index 0000000..ed04028 --- /dev/null +++ b/type/__bird_radv/manifest @@ -0,0 +1,110 @@ +#!/bin/sh -e +# +# 2021 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +os=$(cat "${__global:?}/explorer/os") + +case "$os" in +'alpine'|'debian'|'ubuntu') + confdir='/etc/bird.d' +;; +*) + printf "Your operating system (%s) is currently not supported by __bird_radv\n" "$os" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 +;; +esac + +have_routes=no +if [ -f "${__object:?}/parameter/route" ]; +then + have_routes=yes +fi + +RDNS= +if [ -f "${__object:?}/parameter/ns" ]; +then + RDNS=$(cat << EOF + rdnss { +$(sed -e 's/^/\t\tns /' -e 's/$/;/' "${__object:?}/parameter/ns") + }; + +EOF +) +fi + +DNSSL= +if [ -f "${__object:?}/parameter/dnssl" ]; +then + DNSSL=$(sed -e 's/^/\tdnssl "/' -e 's/$/";/' "${__object:?}/parameter/dnssl") +fi + +MTU= +if [ -f "${__object:?}/parameter/mtu" ]; +then + MTU="link mtu $(cat "${__object:?}/parameter/mtu");" +fi + +DEFAULT_PREFERENCE= +if [ -f "${__object:?}/parameter/default-preference" ]; +then + DEFAULT_PREFERENCE="default preference $(cat "${__object:?}/parameter/default-preference");" +fi + +ROUTE_PREFERENCE= +if [ -f "${__object:?}/parameter/route-preference" ]; +then + ROUTE_PREFERENCE="route preference $(cat "${__object:?}/parameter/route-preference");" +fi + +DEFAULT_LIFETIME= +if [ -f "${__object:?}/parameter/default-lifetime" ]; +then + DEFAULT_LIFETIME="default lifetime $(cat "${__object:?}/parameter/default-lifetime");" +fi + +__file "${confdir:?}/radv-${__object_id:?}.conf" \ + --mode 0640 --owner root --group bird \ + --source - << EOF +ipv6 table radv_routes_${__object_id}; + +protocol static { + description "Routes advertised via RAs"; + ipv6 { table radv_routes_${__object_id}; }; + +$(sed -e 's/^/\troute /' -e 's/$/ unreachable;/' "${__object:?}/parameter/route") +} + +protocol radv ${__object_id:?} { + propagate routes ${have_routes:?}; + ipv6 { table radv_routes_${__object_id}; export all; }; + + interface "$(cat "${__object:?}/parameter/interface")" { + $MTU + $DEFAULT_LIFETIME + $DEFAULT_PREFERENCE + $ROUTE_PREFERENCE + }; + +$RDNS + +$DNSSL + +} +EOF diff --git a/type/__bird_radv/parameter/optional b/type/__bird_radv/parameter/optional new file mode 100644 index 0000000..51058a7 --- /dev/null +++ b/type/__bird_radv/parameter/optional @@ -0,0 +1,4 @@ +mtu +default-preference +route-preference +default-lifetime diff --git a/type/__bird_radv/parameter/optional_multiple b/type/__bird_radv/parameter/optional_multiple new file mode 100644 index 0000000..d3e3505 --- /dev/null +++ b/type/__bird_radv/parameter/optional_multiple @@ -0,0 +1,3 @@ +dnssl +ns +route diff --git a/type/__bird_radv/parameter/required b/type/__bird_radv/parameter/required new file mode 100644 index 0000000..b529896 --- /dev/null +++ b/type/__bird_radv/parameter/required @@ -0,0 +1 @@ +interface diff --git a/type/__bird_static/files/template.sh b/type/__bird_static/files/template.sh new file mode 100755 index 0000000..2a69daf --- /dev/null +++ b/type/__bird_static/files/template.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# Template to generate a static protocol configuration file for bird(1). +# Required non-empty variables: +# __object_id, object +# +# Required defined variables: +# description + +# Header +printf "protocol static %s {\n" "${__object_id:?}" + +# Optional description +[ -n "${description?}" ] && printf "\tdescription \"%s\";\n" "${description:?}" + +# Channel choice +printf "\t%s;\n" "$(cat "${__object:?}/parameter/channel")" + +# Routes +while read -r route +do + printf "\troute %s;\n" "${route?}" +done < "${__object:?}/parameter/route" + +# Header close +printf "}\n" diff --git a/type/__bird_static/man.rst b/type/__bird_static/man.rst new file mode 100644 index 0000000..808f44a --- /dev/null +++ b/type/__bird_static/man.rst @@ -0,0 +1,69 @@ +cdist-type__bird_static(7) +========================== + +NAME +---- +cdist-type__bird_static - configure an instance of the bird static protocol. + + +DESCRIPTION +----------- +This type write the configuration file for an instance of the static protocl to +be ran bu the bird internet routing daemon, allowing an administrator to inject +static routes into the daemon's routing tables. This protocol allows for only +one of two channels to be used, either `ipv4` or `ipv6`, by default `ipv6` is +used unless the `ipv4` flag is passed. This type **expects** to depend on the +`cdist-type__bird_core(7)` type. + + +REQUIRED PARAMETERS +------------------- +channel + The channel to use between the protocol and the table. + +REQUIRED MULTIPLE PARAMETERS +---------------------------- +route + This flag expects a valid route to be inserted between the bird `route` + keyword and the end of line. It may be specified as many times as necessary. + + +OPTIONAL PARAMETERS +------------------- +description + An instance desciption to be printed when `birdc show protocols` is called. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Setup bird and open a BGP session. + __bird_core --router-id 198.51.100.4 + + require='__bird_core' __bird_static static4 \ + --description "static ipv4 routes plugged into bird" \ + --route "198.51.0.0/16 via 192.51.100.1" \ + --route "192.52.0.0/16 via 192.51.100.1" + + +SEE ALSO +-------- +cdist-type__bird_core(7) +cdist-type__bird_bgp(7) +cdist-type__bird_kernel(7) +cdist-type__bird_ospf(7) + + +AUTHORS +------- +Joachim Desroches + + +COPYING +------- +Copyright \(C) 2021 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__bird_static/manifest b/type/__bird_static/manifest new file mode 100755 index 0000000..722971b --- /dev/null +++ b/type/__bird_static/manifest @@ -0,0 +1,51 @@ +#!/bin/sh -e +# +# 2021 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + + +os=$(cat "${__global:?}/explorer/os") + +case "$os" in + 'alpine'|'debian'|'ubuntu') + confdir=/etc/bird.d + ;; + *) + printf "Your operating system (%s) is currently not supported by __bird_static\n" "$os" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +# Required parameter route is directly accessed in template. +# Boolean parameter ipv4 is directly accessed in template. +# Optional parameter description +description= +if [ -f "${__object:?}/parameter/description" ]; +then + description="$(cat "${__object:?}/parameter/description")" +fi +export description + +# Run template +"${__type:?}"/files/template.sh > "${__files:?}/static-${__object_id:?}.conf" + +# Install resulting configuration +__file "${confdir:?}"/static-"${__object_id:?}".conf \ + --mode 0640 --owner root --group bird \ + --source "${__files:?}/static-${__object_id:?}.conf" diff --git a/type/__bird_static/parameter/optional b/type/__bird_static/parameter/optional new file mode 100644 index 0000000..e1b39b0 --- /dev/null +++ b/type/__bird_static/parameter/optional @@ -0,0 +1 @@ +description diff --git a/type/__bird_static/parameter/required b/type/__bird_static/parameter/required new file mode 100644 index 0000000..6dca835 --- /dev/null +++ b/type/__bird_static/parameter/required @@ -0,0 +1 @@ +channel diff --git a/type/__bird_static/parameter/required_multiple b/type/__bird_static/parameter/required_multiple new file mode 100644 index 0000000..6f36346 --- /dev/null +++ b/type/__bird_static/parameter/required_multiple @@ -0,0 +1 @@ +route diff --git a/type/__borg_repo/gencode-remote b/type/__borg_repo/gencode-remote new file mode 100644 index 0000000..f4580ef --- /dev/null +++ b/type/__borg_repo/gencode-remote @@ -0,0 +1,41 @@ +#!/bin/sh + +passphrase= +appendonly= + +case "$(cat "${__object:?}/parameter/encryption")" in + none) + enc=none + ;; + repokey) + enc=repokey + if [ -f "${__object:?}/parameter/passphrase" ]; + then + passphrase="$(cat "${__object:?}/parameter/passphrase")" + else + echo "__borg_repo cannot use repokey encryption with no passphrase. Aborting." >&2; + exit 1; + fi + ;; + *) + echo "$enc is not a known encryption mode for __borg_repo. Aborting." >&2 + exit 1; +esac + +if [ -f "${__object:?}/parameter/append-only" ]; +then + appendonly='--append-only' +fi + +if [ -f "${__object:?}/parameter/owner" ]; +then + doas="sudo -u '$(cat "${__object:?}/parameter/owner")'" +fi + +cat <<- EOF + set -x + if [ ! -d "/${__object_id:?}" ]; then + $doas BORG_NEW_PASSPHRASE=$passphrase borg init -e ${enc:?} $appendonly /${__object_id:?} + fi +EOF + diff --git a/type/__borg_repo/man.rst b/type/__borg_repo/man.rst new file mode 100644 index 0000000..dce3660 --- /dev/null +++ b/type/__borg_repo/man.rst @@ -0,0 +1,46 @@ +cdist-type__borg_repo(7) +======================== + +NAME +---- +cdist-type__borg_repo - Configure a borg repository on host + + +DESCRIPTION +----------- + +Initializes a borg repository at the location specified in the +`${__object_id}`. Nothing is done if the repository already exists. + +Currently, only `none` and `repokey` are supported as encryption modes; +`repokey` requires the `passphrase` argument to be given. The default is +`none`. + +REQUIRED PARAMETERS +------------------- +encryption + The encryption to use. + +OPTIONAL PARAMETERS +------------------- +passphrase + The passphrase to encrypt the keyfile with. + +owner + Remote user owning the repository. + +BOOLEAN PARAMETERS +------------------ +append-only + If the repository is append-only + +AUTHORS +------- +Joachim Desroches + +COPYING +------- +Copyright \(C) 2020 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__borg_repo/manifest b/type/__borg_repo/manifest new file mode 100644 index 0000000..4e4d35e --- /dev/null +++ b/type/__borg_repo/manifest @@ -0,0 +1,20 @@ +#!/bin/sh + +os="$(cat "${__global:?}"/explorer/os)" + +case "$os" in + "alpine"|"ubuntu") + borg_package=borgbackup + ;; + *) + echo "__borg_repo is not yet implemented for os $os. Aborting." >&2; + exit 1; +esac + +__package "$borg_package" + +if [ -f "${__object:?}/parameter/owner" ]; +then + __package sudo +fi + diff --git a/type/__borg_repo/parameter/boolean b/type/__borg_repo/parameter/boolean new file mode 100644 index 0000000..f8ee7c6 --- /dev/null +++ b/type/__borg_repo/parameter/boolean @@ -0,0 +1 @@ +append-only diff --git a/type/__borg_repo/parameter/default/encryption b/type/__borg_repo/parameter/default/encryption new file mode 100644 index 0000000..621e94f --- /dev/null +++ b/type/__borg_repo/parameter/default/encryption @@ -0,0 +1 @@ +none diff --git a/type/__borg_repo/parameter/optional b/type/__borg_repo/parameter/optional new file mode 100644 index 0000000..8e1ddfd --- /dev/null +++ b/type/__borg_repo/parameter/optional @@ -0,0 +1,2 @@ +passphrase +owner diff --git a/type/__borg_repo/parameter/required b/type/__borg_repo/parameter/required new file mode 100644 index 0000000..a5465f8 --- /dev/null +++ b/type/__borg_repo/parameter/required @@ -0,0 +1 @@ +encryption diff --git a/type/__dma/explorer/auth_conf b/type/__dma/explorer/auth_conf new file mode 100755 index 0000000..cef0aca --- /dev/null +++ b/type/__dma/explorer/auth_conf @@ -0,0 +1,49 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# This explorer determines the path of dma's auth.conf file + +# No dma.conf -> use default +test -f /etc/dma/dma.conf || { + echo /etc/dma/auth.conf + exit 0 +} +test -r /etc/dma/dma.conf || { + echo 'Cannot read /etc/dma/dma.conf' >&2 + exit 1 +} + +# Get AUTHPATH from dma.conf +awk -F'[ \t]' ' +{ + sub(/#.*$/, "", $0) # remove comments + if (!$0) next # ignore empty lines +} +$1 == "AUTHPATH" { + # Store authpath. In dma conf parsing last wins. + if ($2) authpath = substr($0, index($0, " ") + 1) +} +END { + if (authpath) { + print authpath + exit 0 + } else exit 1 +} +' /etc/dma/dma.conf \ +|| echo /etc/dma/auth.conf # default diff --git a/type/__dma/explorer/conf b/type/__dma/explorer/conf new file mode 100755 index 0000000..b4d6d26 --- /dev/null +++ b/type/__dma/explorer/conf @@ -0,0 +1,34 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# This explorer returns a sorted list of "active" (= non-commented) lines +# in the dma.conf file. +# "Trailing" line comments are stripped off. +# +# NOTE: This explorer assumes that the sort(1) utility supports the non-POXIX +# -s (stable sort) option. + +CONF_PATH=/etc/dma # set in Makefile +dma_conf="${CONF_PATH:?}/dma.conf" + +test -f "${dma_conf}" || exit 0 + +grep -v -e '^[ \t]*#\|^$' "${dma_conf}" \ +| sed -e 's/[ \t]*#.*$//' \ +| sort -s -k 1,1 diff --git a/type/__dma/files/update_dma_conf.awk b/type/__dma/files/update_dma_conf.awk new file mode 100644 index 0000000..15ef7bf --- /dev/null +++ b/type/__dma/files/update_dma_conf.awk @@ -0,0 +1,178 @@ +#!/usr/bin/awk -f +# +# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . + +function comment_line(line) { + # returns the position in line at which the comment's text starts + # (0 if the line is not a comment) + match(line, /^[ \t]*\#+[ \t]*/) + return RSTART ? (RLENGTH + 1) : 0 +} +function empty_line(line) { return line ~ /^[ \t]*$/ } +function is_word(s) { return s ~ /^[A-Z_]+$/ } # "looks like a plausible word" + +function first(line, sep_re) { + # returns the part of the line until sep is found + # (or the whole line if sep is not found) + if (!sep_re) sep_re = "[" SUBSEP "]" + match(line, sep_re) + return RSTART ? substr(line, 1, RSTART - 1) : line +} + +function rest(line, sep_re) { + # returns the part of the line after the first occurrence of sep is found. + # (or nothing if sep is not found) + if (!sep_re) sep_re = "[" SUBSEP "]" + if (match(line, sep_re)) + return substr(line, RSTART + RLENGTH) +} + +function conf_pop(word, value) { + # returns the next value for the config `word` and delete it from the list. + # if value is set, this function will only return value if it is the first + # option in the list, otherwise it returns 0. + + if (!(word in conf)) return 0 + if (!value) { + if (index(conf[word], SUBSEP)) # more than one element? + value = substr(conf[word], 1, index(conf[word], SUBSEP) - 1) + else + value = conf[word] + } + + if (index(conf[word], SUBSEP)) { + if (index(conf[word], value SUBSEP) != 1) return 0 + conf[word] = substr(conf[word], length(value) + 2) + } else { + if (conf[word] != value) return 0 + delete conf[word] + } + return value +} + +function print_conf(word, value) { + # print a config line with the given parameters + printf "%s", word + if (value) printf " %s", value + printf "\n" +} + +function print_confs(word, value) { + # print config lines for all values stored in conf[word]. + if (!(word in conf)) return + if (conf[word]) { + while (value = conf_pop(word)) + print_conf(word, value) + } else { + print_conf(word) + delete conf[word] + } +} + +BEGIN { + FS = "\n" + EQS = "[ \t]" # copied from dma/conf.c + + if (ARGV[2]) exit (e=1) + + # Loop over file twice! + ARGV[2] = ARGV[1] + ARGC++ + + # read the "should" state into the `conf` array. + while (getline < "/dev/stdin") { + word = first($0, EQS) + if ((word in conf)) + conf[word] = conf[word] SUBSEP rest($0, EQS) + else + conf[word] = rest($0, EQS) + } +} + +# first pass, gather information about where which information is stored in the +# current config file. This information will be used in the second pass. +NR == FNR { + if (comment_line($0)) { + # comment line + word = first(substr($0, comment_line($0)), " ") + if (is_word(word)) last_occ["#" word] = FNR + } else { + word = first($0, EQS) + if (is_word(word)) last_occ[word] = FNR + } +} + +# before second pass prepare hashes containing location information to be used +# in the second pass. +NR > FNR && FNR == 1 { + # First we drop the locations of commented-out options if a non-commented + # option is available. If a non-commented option is available, we will + # append new config options there to have them all at one place. + for (k in last_occ) + if (k ~ /^\#/ && (substr(k, 2) in last_occ)) + delete last_occ[k] + + # Reverse the option => line mapping. The line_map allows for easier lookups + # in the second pass. + for (k in last_occ) line_map[last_occ[k]] = k +} + +# second pass, generate and output new config +NR > FNR { + if (comment_line($0) || empty_line($0)) { + # comment or empty line + print + + if ((FNR in line_map)) { + if (line_map[FNR] ~ /^\#/) { + # This line contains a commented config option. If the conf hash + # contains options to be set, we output them here because this + # option is not used in the current config. + k = substr(line_map[FNR], 2) + if ((k in conf)) print_confs(k) + } + + if (("INSECURE" in conf) && line_map[FNR] ~ /^\#?SECURE$/) { + # INSECURE goes where SECURE comment is. + print_confs("INSECURE") + } + } + } else { + word = first($0, EQS) + value = rest($0, EQS) + sub(/[ \t]*\#.*$/, "", value) # ignore comments in value + + if ((word in conf) && value == first(conf[word])) { + # keep config options we want + conf_pop(word) + print + } + + if ((FNR in line_map) && line_map[FNR] == word) { + # rest of config options should be here + print_confs(word) + } + } +} + +END { + if (e) exit + + # print rest of config options ( + for (word in conf) print_confs(word) +} diff --git a/type/__dma/gencode-remote b/type/__dma/gencode-remote new file mode 100755 index 0000000..580b22e --- /dev/null +++ b/type/__dma/gencode-remote @@ -0,0 +1,177 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +quote() { printf "'%s'" "$(printf '%s' "$*" | sed -e "s/'/'\\\\''/g")"; } +drop_awk_comments() { quote "$(sed '/^[[:blank:]]*#.*$/d;/^$/d' "$@")"; } + +CONF_PATH=/etc/dma # set in Makefile + +# Determine mailname +if test -f "${__object:?}/parameter/mailname" +then + mailname=$(cat "${__object:?}/parameter/mailname") +else + case $(cat "${__global:?}/explorer/os") + in + (debian|devuan|ubuntu) + # On Debian-like systems use /etc/mailname unless --mailname is used + mailname='/etc/mailname' + ;; + (*) + mailname=${__target_fqdn:?} + ;; + esac +fi + + +# Generate "should" values for config +conf_should=$( + if test -s "${__object:?}/parameter/smarthost" + then + printf 'SMARTHOST %s\n' "$(cat "${__object:?}/parameter/smarthost")" + fi + + printf 'MAILNAME %s\n' "${mailname}" + + if test -s "${__object:?}/explorer/auth_conf" + then + printf "AUTHPATH %s\n" "$(cat "${__object:?}/explorer/auth_conf")" + fi + + case $(cat "${__object:?}/parameter/security") + in + (ssl|tls) + default_smtp_port=465 + echo 'SECURETRANSFER' + ;; + (starttls) + default_smtp_port=587 + echo 'SECURETRANSFER' + echo 'STARTTLS' + ;; + (opportunistic) + default_smtp_port=25 + echo 'SECURETRANSFER' + echo 'STARTTLS' + echo 'OPPORTUNISTIC_TLS' + ;; + (insecure) + default_smtp_port=25 + echo 'INSECURE' + ;; + esac + + if test -s "${__object:?}/parameter/port" + then + printf 'PORT %u\n' "$(cat "${__object:?}/parameter/port")" + elif test "${default_smtp_port}" -ne 25 # DMA uses port 25 by default + then + printf 'PORT %u\n' "${default_smtp_port}" + fi + + if test -f "${__object:?}/parameter/masquerade" + then + while read -r line + do + printf 'MASQUERADE %s\n' "${line}" + done <"${__object:?}/parameter/masquerade" + fi + + if test -f "${__object:?}/parameter/defer" + then + echo 'DEFER' + fi + + if test -f "${__object:?}/parameter/fullbounce" + then + echo 'FULLBOUNCE' + fi + + if test -f "${__object:?}/parameter/nullclient" + then + test -s "${__object:?}/parameter/smarthost" || { + echo '--nullclient requires a --smarthost to be defined' >&2 + exit 1 + } + + echo 'NULLCLIENT' + fi +) +# Sort conf_should to compare against "conf_is" +conf_should=$(echo "${conf_should}" | sort -s -k 1,1) + +config_updated=false +if ! echo "${conf_should}" | cmp -s "${__object:?}/explorer/conf" - +then + # config needs to be updated + dma_conf="${CONF_PATH:?}/dma.conf" + + # The following AWK script will output the new config file to be stored on + # disk. To do so it reads the current dma.conf file and the config options + # that should be set (from stdin). + # Note that the path to the current dma.conf is passed to AWK twice, because + # the new file cannot be generated in one pass. + + # The logic tries to place options at a sensible location, that is: + # a) if the option is already used in the config file: + # group all similar options (e.g. MASQUERADE) at one place in the order + # they are listed in stdin. + # b) if it is a new option and a "default comment" (e.g. "#PORT 25") exists: + # place options grouped directly after the comment (the comment is left + # alone) + # c) otherwise: + # options are grouped by word (the first word in the line) and appended + # at the end of the file. + + cat <<-CODE + awk $(drop_awk_comments "${__type:?}/files/update_dma_conf.awk") $(quote "${dma_conf}") <<'EOF' >$(quote "${dma_conf}.tmp") \ + && cat $(quote "${dma_conf}.tmp") >$(quote "${dma_conf}") + ${conf_should} + EOF + rm $(quote "${dma_conf}.tmp") + CODE + + config_updated=true + echo 'config updated' >>"${__messages_out:?}" +fi + + +# Send a test email if enabled and necessary (=configuration changed) +if test -f "${__object:?}/parameter/send-test-mail" +then + if grep -q '^__mail_alias/root:' "${__messages_in:?}" \ + || grep -q '^__dma_auth/' "${__messages_in:?}" \ + || ${config_updated} + then + cat <<-CODE + sendmail root <<'EOF' + Subject: [cdist] Test mail from '${__target_fqdn:?}' + + Hi, + + you can ignore this message. + Its sole purpose is to notify you that root mail on ${__target_fqdn:?} + will be redirected to you. + + Enjoy! + EOF + CODE + fi +fi diff --git a/type/__dma/man.rst b/type/__dma/man.rst new file mode 100644 index 0000000..29a71fa --- /dev/null +++ b/type/__dma/man.rst @@ -0,0 +1,112 @@ +cdist-type__dma(7) +============================ + +NAME +---- +cdist-type__dma - Setup the DragonFly Mail Agent as the MTA. + + +DESCRIPTION +----------- +This (singleton) type uses DMA, a small Mail Transport Agent (MTA), to accept +mails from locally installed Mail User Agents (MUA) and either deliver the mails +to a remote smart host for delivery or communicate with remote SMTP servers +directly. + + +REQUIRED PARAMETERS +------------------- +None. + + +BOOLEAN PARAMETERS +------------------ +defer + If enabled, mail will not be sent immediately, but stored in a queue. + To flush the queue and send the mails, ```dma -q`` has to be run + periodically (e.g. using a cron job.) + This type does not manage such a cron job, but some operating systems ship + such a cron job with the package. +fullbounce + Enable if bounce messages should include the complete original message, + not just the headers. +nullclient + Enable to bypass aliases and local delivery, and instead forward all mails + to the defined ``--smarthost``. +send-test-mail + If set, this type will send a test email to root after setup, to check if + the configured settings work. + + +OPTIONAL PARAMETERS +------------------- +mailname + If present, this will be the hostname used to identify this host and the + remote part of the sender addresses. + If not defined, it defaults to ``/etc/mailname`` on Debian derivatives and + to ``__target_fqdn`` otherwise. + See `dma(8)` for more information. + + Note: on Debian derivatives the ``/etc/mailname`` file should be updated + instead of using this parameter. +masquerade + Masquerade the envelope-from addresses with this address/hostname. + Use this setting if mails are not accepted by destination mail servers + because your sender domain is invalid. + This option can be used multiple times. + For more information see the `dma(8)` man page. +port + The port on which to deliver email. + If not provided, a sensible default port will be used based on the + ``--security`` argument. +security + Configures whether and how DMA should use secure connections. + + ssl/tls + Enable TLS/SSL secured transfer. + starttls + Use STARTTLS to establish a secure connection. + opportunistic (default) + Will try to establish a secure connection using STARTTLS, but allow + unencrypted transfer if STARTTLS fails. + Most useful when dma is used without a smarthost, delivering remote + messages directly to the outside mail exchangers. + insecure + allow plain text SMTP login over an insecure connection. + Should really *not* be used anymore! +smarthost + The mail server used to send email. + It must be configured to act as a relay for the host being configured by + this type so that mail can be sent to users non-local to the smarthost. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Install DMA and use the smarthost mx1.domain.tld to send mail. + __dma --smarthost mx1.domain.tld --send-test-mail + + # Install DMA in a default configuration. + __dma + + +SEE ALSO +-------- +- `DragonFly Mail Agent `_ +- `DragonFly Handbook MTA `_ + + +AUTHORS +------- +Evilham +Dennis Camera + + +COPYING +------- +Copyright \(C) 2020 Evilham and Dennis Camera. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__dma/manifest b/type/__dma/manifest new file mode 100755 index 0000000..530ad09 --- /dev/null +++ b/type/__dma/manifest @@ -0,0 +1,66 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +os=$(cat "${__global:?}/explorer/os") + +# Install DMA +case ${os} +in + (alpine) + __package dma --state present + export require='__package/dma' + ;; + (debian|devuan|ubuntu) + __package dma --state present + export require='__package/dma' + ;; + (freebsd) + # Stop sendmail if necessary + __process 'sendmail' --name 'sendmail.*' --state absent \ + --stop '/etc/rc.d/sendmail onestop' + + # ... and disable it + __key_value 'rcconf-sendmail-enable' --file '/etc/rc.conf' \ + --key 'sendmail_enable' --delimiter '=' --value '"NONE"' \ + --exact_delimiter + + # Setup mailwrapper accordingly + __file '/etc/mail/mailer.conf' --mode 0644 --source - <<-'EOF' + # + # Execute the "real" sendmail program, named /usr/libexec/sendmail/sendmail + # + sendmail /usr/libexec/dma + send-mail /usr/libexec/dma + mailq /usr/libexec/dma + newaliases /usr/libexec/dma + rmail /usr/libexec/dma + EOF + ;; + (*) + cat <&2 +Your OS (${os}) is not supported yet. + +Maybe adding support is as simple as adapting the packages or allowing it, +we highly encourage you to open a PR with the necessary changes. +See: https://code.ungleich.ch/ungleich-public/cdist-contrib/ +EOF + exit 1 + ;; +esac diff --git a/type/__dma/parameter/boolean b/type/__dma/parameter/boolean new file mode 100644 index 0000000..523bb97 --- /dev/null +++ b/type/__dma/parameter/boolean @@ -0,0 +1,4 @@ +defer +fullbounce +nullclient +send-test-mail diff --git a/type/__dma/parameter/default/security b/type/__dma/parameter/default/security new file mode 100644 index 0000000..9f1e0a6 --- /dev/null +++ b/type/__dma/parameter/default/security @@ -0,0 +1 @@ +opportunistic diff --git a/type/__dma/parameter/optional b/type/__dma/parameter/optional new file mode 100644 index 0000000..615c189 --- /dev/null +++ b/type/__dma/parameter/optional @@ -0,0 +1,4 @@ +mailname +port +security +smarthost diff --git a/type/__dma/parameter/optional_multiple b/type/__dma/parameter/optional_multiple new file mode 100644 index 0000000..70f4146 --- /dev/null +++ b/type/__dma/parameter/optional_multiple @@ -0,0 +1 @@ +masquerade diff --git a/type/__dma/singleton b/type/__dma/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__dma_auth/explorer/auth_conf b/type/__dma_auth/explorer/auth_conf new file mode 120000 index 0000000..e89de93 --- /dev/null +++ b/type/__dma_auth/explorer/auth_conf @@ -0,0 +1 @@ +../../__dma/explorer/auth_conf \ No newline at end of file diff --git a/type/__dma_auth/explorer/state b/type/__dma_auth/explorer/state new file mode 100755 index 0000000..c829cd4 --- /dev/null +++ b/type/__dma_auth/explorer/state @@ -0,0 +1,91 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# This explorer looks for a line matching the server parameter +# in dma's auth.conf and reports: +# present: a line matching login + host + password exists +# absent: no line matching login + host exists +# different_login: a line exists but with a different login user +# different_password: a line exists but with a different password +# multiple: multiple lines matching host exist (should not happen) + +auth_conf=$("${__type_explorer:?}/auth_conf") +test -r "${auth_conf}" || exit 0 + +awk -F'\n' ' +function getvalue(path) { + # Reads the first line of the file located at path and returns it. + getline < path + close(path) + return $0 +} + +BEGIN { + DP = "[: \t]" # copied from dma/conf.c + + parameter_dir = ENVIRON["__object"] "/parameter/" + + # Read the parameters of this object + host_param = ENVIRON["__object_id"] + login_param = getvalue(parameter_dir "login") + passwd_param = getvalue(parameter_dir "password") + + state = "absent" +} + +/^#/ || /^$/ { + # skip comments and empty lines + next +} + +{ + # parse line + + login = substr($0, 1, index($0, "|") - 1) + if (!login) { login = $0 } # if no "|" found + + host = substr($0, length(login) + 2) + + if (match(host, DP)) { + passwd = substr(host, RSTART + 1) + host = substr(host, 1, RSTART - 1) + } else { + passwd = "" + } +} + +host == host_param { + # a match… + if (state == "absent") { + if (login != login_param) + state = "different_login" + else if (passwd != passwd_param) + state = "different_password" + else + state = "present" + } else { + # report "multiple" to that the type can remove the duplicates. + state = "multiple" + } +} + +END { + print state +} +' "${auth_conf}" diff --git a/type/__dma_auth/files/update_dma_auth.awk b/type/__dma_auth/files/update_dma_auth.awk new file mode 100644 index 0000000..c50198b --- /dev/null +++ b/type/__dma_auth/files/update_dma_auth.awk @@ -0,0 +1,93 @@ +#!/usr/bin/awk -f +# +# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +function getvalue(path) { + # Reads the first line of the file located at path and returns it. + getline < path + close(path) + return $0 +} + +function print_should() { + printf "%s|%s:%s\n", login_param, host_param, passwd_param +} + +BEGIN { + FS = "\n" + DP = "[: \t]" # copied from dma/conf.c + + parameter_dir = ENVIRON["__object"] "/parameter/" + + mode = (getvalue(parameter_dir "state") != "absent") + + host_param = ENVIRON["__object_id"] + login_param = getvalue(parameter_dir "login") + passwd_param = getvalue(parameter_dir "password") +} + +# skip comments and empty lines +/^#/ || /^$/ { + print + next +} + +{ + # parse line (like dma/conf.c would) + + login = substr($0, 1, index($0, "|") - 1) + if (!login) { login = $0 } # if no "|" found + + host = substr($0, length(login) + 2) + + if (match(host, DP)) { + passwd = substr(host, RSTART + 1) + host = substr(host, 1, RSTART - 1) + } else { + passwd = "" + } +} + +host == host_param { + if (mode) { + # state_should == present + if (!written) { + # replace first line if host matches (but only if no line has + # been written already -> no duplicates) + print_should() + written = 1 + } + next + } else { + # state_should == absent + next + } +} + +# leave other lines alone +{ + print +} + +END { + if (mode && !written) { + # append line if no match to replace was found + print_should() + } +} diff --git a/type/__dma_auth/gencode-remote b/type/__dma_auth/gencode-remote new file mode 100755 index 0000000..b6a0100 --- /dev/null +++ b/type/__dma_auth/gencode-remote @@ -0,0 +1,72 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +quote() { printf "'%s'" "$(printf '%s' "$*" | sed -e "s/'/'\\\\''/g")"; } +drop_awk_comments() { quote "$(sed '/^[[:blank:]]*#.*$/d;/^$/d' "$@")"; } + +state_is=$(cat "${__object:?}/explorer/state") +state_should=$(cat "${__object:?}/parameter/state") + +server=${__object_id:?} +login=$(cat "${__object:?}/parameter/login") + + +auth_conf=$(cat "${__object:?}/explorer/auth_conf") +test -n "${auth_conf}" || { + echo 'Cannot determine path of dma auth.conf' >&2 + exit 1 +} + +if test "${state_is}" = "${state_should}" +then + # state is as it should + exit 0 +fi + +case ${state_should} +in + (present) + test -n "${login}" || { echo '--login must be non-empty' >&2; exit 1; } + + if test "${state_is}" = 'absent' + then + printf 'add authuser %s on %s\n' "${login}" "${server}" >>"${__messages_out:?}" + else + printf 'set authuser %s on %s\n' "${login}" "${server}" >>"${__messages_out:?}" + fi + ;; + (absent) + printf 'delete authuser %s on %s\n' "${login}" "${server}" >>"${__messages_out:?}" + ;; + (*) + printf 'Invalid --state: %s.\n' "${state_should}" >&2 + printf 'Acceptable values are: present, absent.\n' >&2 + exit 1 + ;; +esac + + +cat <$(quote "${auth_conf}.tmp") \ +&& cat $(quote "${auth_conf}.tmp") >$(quote "${auth_conf}") +rm -f $(quote "${auth_conf}.tmp") +EOF diff --git a/type/__dma_auth/man.rst b/type/__dma_auth/man.rst new file mode 100644 index 0000000..da76883 --- /dev/null +++ b/type/__dma_auth/man.rst @@ -0,0 +1,66 @@ +cdist-type__dma_auth(7) +======================= + +NAME +---- +cdist-type__dma_auth - Configure SMTP logins for the DragonFly Mail Agent MTA. + + +DESCRIPTION +----------- +This cdist type allows you to set up credentials to log in to remote SMTP +servers. + +NB: dma currently (v0.13) does not differentiate between users on a host. + It will use whatever user it finds in the ``auth.conf`` first. + Thus, this type will use the ``__object_id`` as the host specifier. + + +REQUIRED PARAMETERS +------------------- +login + The user's LOGIN name on the SMTP server. +password + The user's password (in plain text.) + + +OPTIONAL PARAMETERS +------------------- +state + Either ``present`` or ``absent``. Defaults to ``present``. + +BOOLEAN PARAMETERS +------------------ +None. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Set the password for smarthost + __dma_auth smarthost.example.com --login joe --password hunter2 + + # Set credentials for user at an external provider + __dma_auth mail.provider.com --login paul@example.com --password letmein + + # Delete credentials for example.com (for all users) + __dma_auth example.com --login '' --password '' --state absent + +SEE ALSO +-------- +:strong:`cdist-type__dma`\ (7), :strong:`dma`\ (8) + + +AUTHORS +------- +Dennis Camera + + +COPYING +------- +Copyright \(C) 2020 Dennis Camera. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__dma_auth/nonparallel b/type/__dma_auth/nonparallel new file mode 100644 index 0000000..e69de29 diff --git a/type/__dma_auth/parameter/default/state b/type/__dma_auth/parameter/default/state new file mode 100644 index 0000000..e7f6134 --- /dev/null +++ b/type/__dma_auth/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/type/__dma_auth/parameter/optional b/type/__dma_auth/parameter/optional new file mode 100644 index 0000000..ff72b5c --- /dev/null +++ b/type/__dma_auth/parameter/optional @@ -0,0 +1 @@ +state diff --git a/type/__dma_auth/parameter/required b/type/__dma_auth/parameter/required new file mode 100644 index 0000000..ae3c622 --- /dev/null +++ b/type/__dma_auth/parameter/required @@ -0,0 +1,2 @@ +login +password diff --git a/type/__jitsi_meet/explorer/configured-memory b/type/__jitsi_meet/explorer/configured-memory new file mode 100755 index 0000000..658f94b --- /dev/null +++ b/type/__jitsi_meet/explorer/configured-memory @@ -0,0 +1,15 @@ +#!/bin/sh -eu + +JICOFO="/usr/share/jicofo/jicofo.sh" +VIDEOBRIDGE="/usr/share/jitsi-videobridge/lib/videobridge.rc" + +if [ -f "${JICOFO:?}" ]; then + jicofo_memory="$(grep JICOFO_MAX_MEMORY= "${JICOFO:?}" | cut -d= -f 2 | cut -d ";" -f 1)" +fi +if [ -f "${VIDEOBRIDGE:?}" ]; then + vb_memory="$(grep VIDEOBRIDGE_MAX_MEMORY= "${VIDEOBRIDGE:?}" | cut -d= -f 2)" +fi +cat < + + +COPYING +------- +Copyright \(C) 2022 Evilham. diff --git a/type/__jitsi_meet/manifest b/type/__jitsi_meet/manifest new file mode 100755 index 0000000..0c210a3 --- /dev/null +++ b/type/__jitsi_meet/manifest @@ -0,0 +1,331 @@ +#!/bin/sh -e + +os="$(cat "${__global}/explorer/os")" +case "${os}" in + devuan|debian) + ;; + *) + echo "Your OS '${os}' is currently not supported." > /dev/stderr + exit 1 + ;; +esac + +current_conferences="$(cat "${__object}/explorer/jitsi-status" | grep -E "^jitsi_conferences[[:space:]]" | cut -d ' ' -f 2)" + +JICOFO_AUTHPASSWORD="$(cat "${__object}/explorer/jicofo-authpassword")" +if [ -z "${JICOFO_AUTHPASSWORD}" ]; then + # This is probably a first time installation, we'll generate the + # password which will be set in debconf by this type + # https://github.com/jitsi/jicofo/blob/aafb61b5363a1c4abdbf08e1444a6276b807993e/debian/postinst#L43 + JICOFO_AUTHPASSWORD="$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 16)" +fi + +ABORT_CONFERENCE_COUNT="$(cat "${__object}/parameter/abort-conference-count")" + +if [ -n "${current_conferences}" ] && [ -n "${ABORT_CONFERENCE_COUNT}" ] && \ + [ "${ABORT_CONFERENCE_COUNT}" -le "${current_conferences}" ]; then + cat <<-EOF +Early bail out was requested when at least ${ABORT_CONFERENCE_COUNT} conferences are taking place. +There are currently ${current_conferences} active conferences. + +Try again at a later time or remove or increase --abort-conference-count + EOF + exit 1 +fi + +JITSI_HOST="${__target_host}" +if [ -f "${__object}/parameter/jitsi-version" ]; then + # This has been deprecated and will be removed 'soon' + JITSI_VERSION="$(cat "${__object}/parameter/jitsi-version")" +else + # Note this won't be a parameter anymore, we won't let users stay behind + JITSI_VERSION="$(cat "${__type}/files/jitsi-version")" +fi +TURN_SERVER="$(cat "${__object}/parameter/turn-server")" +TURN_SECRET="$(cat "${__object}/parameter/turn-secret")" + +if [ -z "${TURN_SERVER}" ]; then + TURN_SERVER="${JITSI_HOST}" +fi + +# The rest is loosely based on Jitsi's documentation +# https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-quickstart + +# Setup repositories +## First the signing keys +### Remove old signing key +__apt_key "jitsi_meet_2016" \ + --keyid "66A9 CD05 95D6 AFA2 4729 0D3B EF8B 479E 2DC1 389C" \ + --use-deprecated-apt-key \ + --state "absent" +### Add new signing key +require="__apt_key/jitsi_meet_2016" __apt_key jitsi_meet_2021 \ + --source "${__type}/files/apt_2021.gpg" \ + --state "present" +## Now the repositories (they are a tad weird, so distribution is 'stable/') +require="__apt_key/jitsi_meet_2021" __apt_source jitsi_meet \ + --uri 'https://download.jitsi.org' \ + --distribution 'stable/' \ + --state present +## Ensure apt cache is up-to-date +require="__apt_source/jitsi_meet" __apt_update_index + +export require="${require} __apt_source/jitsi_meet __apt_update_index" + +# Pre-feed debconf settings, so Jitsi's installation has a good config +# shellcheck source=type/__jitsi_meet/files/debconf_settings.sh +. "${__type}/files/debconf_settings.sh" # This defines DEBCONF_SETTINGS +__debconf_set_selections jitsi_meet --line "${DEBCONF_SETTINGS}" +export require="${require} __debconf_set_selections/jitsi_meet" + +# Install and upgrade packages as needed +# NOTE: we are doing version pinning again, but it breaks sometimes when +# the version is not the latest. +# This happens because dependencies might not be properly resolved. +# To avoid this, this type must be maintained up to date. +# If we don't use this, keeping Jitsi's up to date is very difficult. +__package_apt jitsi-meet --version "${JITSI_VERSION}" + +# Proceed only after installation/upgrade has finished +export require="__package_apt/jitsi-meet" + +# TODO: generalise and move out +# Prep nginx for acme settings + +NGINX_ETC="/etc/nginx" + +# +# Setup the acme-challenge snippet +# +__directory "${NGINX_ETC}/snippets" --state present +require="__directory${NGINX_ETC}/snippets" __file "${NGINX_ETC}/snippets/acme-challenge.conf" \ + --mode 644 \ + --source - << EOF +# This file is managed remotely, all changes will be lost + +# This was heavily inspired by debops.org. + +# Automatic Certificate Management Environment (ACME) support. +# https://tools.ietf.org/html/draft-ietf-acme-acme-01 +# https://en.wikipedia.org/wiki/Automated_Certificate_Management_Environment + + +# Return the ACME challenge present in the server public root. +# If not found, switch to global web server root. +location ^~ /.well-known/acme-challenge/ { + default_type "text/plain"; + try_files \$uri @well-known-acme-challenge; +} + +# Return the ACME challenge present in the global server public root. +# If not present, redirect request to a specified domain. +location @well-known-acme-challenge { + root /usr/share/jitsi-meet; + default_type "text/plain"; + try_files \$uri @redirect-acme-challenge; +} + +# Redirect the ACME challenge to a different host. If a redirect loop is +# detected, return 404. +location @redirect-acme-challenge { + if (\$arg_redirect) { + return 404; + } + return 307 \$scheme://${ACME_DOMAIN}\$request_uri?redirect=yes; +} + +# Return 404 if ACME challenge well known path is accessed directly. +location = /.well-known/acme-challenge/ { + return 404; +} +EOF + +__directory "${NGINX_ETC}/sites-available" --state present +require="__directory${NGINX_ETC}/sites-available" __file "${NGINX_ETC}/sites-available/default" \ + --mode 644 \ + --source - << EOF +# This file is managed remotely, all changes will be lost + +server_names_hash_bucket_size 64; + +types { +# nginx's default mime.types doesn't include a mapping for wasm or wav. + application/wasm wasm; + audio/wav wav; +} + +server { + + # Listen on IPv4 + listen 80; + # Note: there is an ipv6only=off flag, but it is Linux-only + # incidentally, that defaults to "on", which is what causes + # not having the double listen to listen on IPv6-only + listen [::]:80; + + server_name welcome; + + root /srv/www/sites/welcome/public; + + include snippets/acme-challenge.conf; + + location / { + return 301 https://\$host\$request_uri; + } +} +EOF + +# Starting from 2.0.7210, jitsi defines following nginx upstreams +__directory "${NGINX_ETC}/conf.d" --state present +require="__directory${NGINX_ETC}/conf.d" __file "${NGINX_ETC}/conf.d/prosody.conf" \ + --mode 644 \ + --source - << EOF +upstream prosody { + zone upstreams 64K; + server 127.0.0.1:5280; + keepalive 2; +} +EOF +require="__directory${NGINX_ETC}/conf.d" __file "${NGINX_ETC}/conf.d/jvb1.conf" \ + --mode 644 \ + --source - << EOF +upstream jvb1 { + zone upstreams 64K; + server 127.0.0.1:9090; + keepalive 2; +} +EOF +require="__directory${NGINX_ETC}/conf.d" __file "${NGINX_ETC}/conf.d/jicofo.conf" \ + --mode 644 \ + --source - << EOF +upstream jicofo { + zone upstreams 64K; + server 127.0.0.1:8888; + keepalive 2; +} +EOF + +if [ -f "${__object}/parameter/secured-domains" ]; then + SECURED_DOMAINS_STATE='present' +else + SECURED_DOMAINS_STATE='absent' +fi + +# This is the main host config +PROSODY_MAIN_CONFIG="YES" +# Prosody settings for common components (jvb, focus, ...) +# shellcheck source=type/__jitsi_meet/files/prosody.cfg.lua.sh +. "${__type}/files/prosody.cfg.lua.sh" # This defines PROSODY_CONFIG +__file "/etc/prosody/conf.d/00_jitsi_base.cfg.lua" \ + --group prosody \ + --mode 0440 \ + --source - < +EOF + +# These two should be changed on new release +EXPORTER_VERSION="1.2.1" +EXPORTER_CHECKSUM="sha256:46d4b8475b72fd7632a5203f1cc3c7067bed4629902b7780a1da85e4e06c2129" +EXPORTER_URL="https://github.com/systemli/prometheus-jitsi-meet-exporter/releases/download/${EXPORTER_VERSION}/prometheus-jitsi-meet-exporter_${EXPORTER_VERSION}_linux_amd64.tar.gz" +if [ -f "${__object}/parameter/disable-prometheus-exporter" ]; then + EXPORTER_STATE="absent" +else + EXPORTER_STATE="present" +fi +__single_binary_service prometheus-jitsi-meet-exporter \ + --state "${EXPORTER_STATE}" \ + --do-not-manage-user \ + --user "nobody" \ + --group "nogroup" \ + --version "${EXPORTER_VERSION}" \ + --checksum "${EXPORTER_CHECKSUM}" \ + --url "${EXPORTER_URL}" \ + --unpack \ + --service-args "-videobridge-url 'http://localhost:8080/colibri/stats' -web.listen-address ':9888'" + +# +# Setup interpreter assets if requested +# See: https://gitlab.com/mfmt/jsi/ +# +jsi_updated_on="2022-04-21" +__link "/usr/share/jitsi-meet/interpreters.html" \ + --type symbolic \ + --source "/opt/jsi/static/index.html.sample" +__directory /opt/jsi --mode 0755 +export require="__directory/opt/jsi" +__download /opt/jsi/jsi.tar.gz \ + --url 'https://gitlab.com/mfmt/jsi/-/archive/1d2cceaf615ee61c0bba80e5bddc61c5d1018303/jsi-1d2cceaf615ee61c0bba80e5bddc61c5d1018303.tar.gz' \ + --sum "sha256:b020141093daa9937507b098f358d0be994834c3e23866a457fc5140415a0c53" +export require="__download/opt/jsi/jsi.tar.gz" +__unpack /opt/jsi/jsi.tar.gz \ + --preserve-archive \ + --tar-strip 1 \ + --destination /opt/jsi/static \ + --onchange "$(cat <]*(/external_api.js).!src='\1'!" \ + -e "s!

[^<]*

!

Jitsi Meetings with interpreter

!" \ + -e "s!https://meet.mayfirst.org!/!" \ + -e "s!(style.css|jsi.js)([^?])!\1?v=${jsi_updated_on:?}\2!" \ + /opt/jsi/static/index.html.sample +EOF +)" diff --git a/type/__jitsi_meet/parameter/boolean b/type/__jitsi_meet/parameter/boolean new file mode 100644 index 0000000..26d95b7 --- /dev/null +++ b/type/__jitsi_meet/parameter/boolean @@ -0,0 +1,2 @@ +disable-prometheus-exporter +secured-domains diff --git a/type/__jitsi_meet/parameter/default/abort-conference-count b/type/__jitsi_meet/parameter/default/abort-conference-count new file mode 100644 index 0000000..e69de29 diff --git a/type/__jitsi_meet/parameter/default/turn-server b/type/__jitsi_meet/parameter/default/turn-server new file mode 100644 index 0000000..e69de29 diff --git a/type/__jitsi_meet/parameter/deprecated/jitsi-version b/type/__jitsi_meet/parameter/deprecated/jitsi-version new file mode 100644 index 0000000..288d647 --- /dev/null +++ b/type/__jitsi_meet/parameter/deprecated/jitsi-version @@ -0,0 +1,4 @@ +Supporting different versions lead to strange issues in the life-time of a +Jitsi instance. Chiefly: difficulties upgrading. + +If you are specifying this for a valid reason, please get in touch. diff --git a/type/__jitsi_meet/parameter/optional b/type/__jitsi_meet/parameter/optional new file mode 100644 index 0000000..e18bd6a --- /dev/null +++ b/type/__jitsi_meet/parameter/optional @@ -0,0 +1,4 @@ +abort-conference-count +jitsi-version +turn-secret +turn-server diff --git a/type/__jitsi_meet/singleton b/type/__jitsi_meet/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__jitsi_meet_domain/boolean b/type/__jitsi_meet_domain/boolean new file mode 100644 index 0000000..9c2e510 --- /dev/null +++ b/type/__jitsi_meet_domain/boolean @@ -0,0 +1 @@ +secured-domains diff --git a/type/__jitsi_meet_domain/files/_update_jitsi_configurations.sh b/type/__jitsi_meet_domain/files/_update_jitsi_configurations.sh new file mode 100755 index 0000000..31ac655 --- /dev/null +++ b/type/__jitsi_meet_domain/files/_update_jitsi_configurations.sh @@ -0,0 +1,35 @@ +#!/bin/sh -eu + +# This is a helper to update the '.sh.orig' files for jitsi's +# configuration files. +# Then the changes must be propagated to their corresponding .sh +# files by the type maintainer or a contributor + +# We could automate this, but are using it as an indicator for the +# latest branch with which we conciliated changes. +BRANCH="jitsi-meet_10655" +REPO="https://github.com/jitsi/jitsi-meet" + +get_url() { + file="${1}" + printf "%s/raw/stable/%s/%s" "${REPO}" "${BRANCH}" "${file}" + +} + +download_file() { + file="${1}" + destination="${2:-${file}.sh.orig}" + url="$(get_url "${file}")" + echo "Downloading ${destination}" + curl -L "${url}" > "${destination}" + echo +} + +download_file config.js +download_file interface_config.js +download_file doc/debian/jitsi-meet/jitsi-meet.example nginx.sh.orig +download_file doc/debian/jitsi-meet-prosody/prosody.cfg.lua-jvb.example prosody.cfg.lua.sh.orig + +# Change the version file, maintainers should check that it matches +# the deb version +printf "2.0.%s-1" "${BRANCH#*_}" > jitsi-version diff --git a/type/__jitsi_meet_domain/files/config.js.sh b/type/__jitsi_meet_domain/files/config.js.sh new file mode 100644 index 0000000..ff976b2 --- /dev/null +++ b/type/__jitsi_meet_domain/files/config.js.sh @@ -0,0 +1,1938 @@ +#!/bin/sh -e + +# shellcheck disable=SC2034 # This is intended to be included +JITSI_CONFIG_JS="$(cat <. + // NOTE [cdist]: if we use '${DOMAIN}', jicofo won't start the meeting + authdomain: '${JITSI_HOST}', + + // Focus component domain. Defaults to focus.. + focus: 'focus.${JITSI_HOST}', + + // XMPP MUC domain. FIXME: use XEP-0030 to discover it. + muc: 'conference.${DOMAIN}' + }, + + // BOSH URL. FIXME: use XEP-0156 to discover it. + // useful for multidomain scenario -> src https://community.jitsi.org/t/same-jitsi-meet-instance-with-multiple-domain-names/17391/2 + bosh: 'https:///http-bind', + + // Websocket URL (XMPP) + websocket: 'wss://${DOMAIN}/' + subdir + 'xmpp-websocket', + + // websocketKeepAliveUrl: 'https://${DOMAIN}/' + subdir + '_unlock', + + // Whether BOSH should be preferred over WebSocket if both are configured. + // preferBosh: false, + + // The real JID of focus participant - can be overridden here + // Do not change username - FIXME: Make focus username configurable + // https://github.com/jitsi/jitsi-meet/issues/7376 + focusUserJid: 'focus@auth.${JITSI_HOST}', + + // Option to send conference requests to jicofo over http (requires nginx rule for it) + // conferenceRequestUrl: + // 'https:///' + subdir + 'conference-request/v1', + + // Options related to the bridge (colibri) data channel + bridgeChannel: { + // If the backend advertises multiple colibri websockets, this options allows + // to filter some of them out based on the domain name. We use the first URL + // which does not match ignoreDomain, falling back to the first one that matches + // ignoreDomain. Has no effect if undefined. + // ignoreDomain: 'example.com', + + // Prefer SCTP (WebRTC data channels over the media path) over a colibri websocket. + // If SCTP is available in the backend it will be used instead of a WS. Defaults to + // false (SCTP is used only if available and no WS are available). + // preferSctp: false + }, + + // Testing / experimental features. + // + + testing: { + // Allows the setting of a custom bandwidth value from the UI. + // assumeBandwidth: true, + + // Enables use of getDisplayMedia in electron + // electronUseGetDisplayMedia: false, + + // Enables AV1 codec for FF. Note: By default it is disabled. + // enableAV1ForFF: false, + + // Enables the use of the codec selection API supported by the browsers . + // enableCodecSelectionAPI: false, + + // P2P test mode disables automatic switching to P2P when there are 2 + // participants in the conference. + // p2pTestMode: false, + + // Enables the test specific features consumed by jitsi-meet-torture + // testMode: false, + + // Disables the auto-play behavior of *all* newly created video element. + // This is useful when the client runs on a host with limited resources. + // noAutoPlayVideo: false, + + // Experiment: Whether to skip interim transcriptions. + // skipInterimTranscriptions: false, + + // Dump transcripts to a element for debugging. + // dumpTranscript: false, + + // Log the audio levels. + // debugAudioLevels: true, + + // Will replace ice candidates IPs with invalid ones in order to fail ice. + // failICE: true, + + // When running on Spot TV, this controls whether to show the recording consent dialog. + // If false (default), Spot instances will not show the recording consent dialog. + // If true, Spot instances will show the recording consent dialog like regular clients. + // showSpotConsentDialog: false, + }, + + // Disables moderator indicators. + // disableModeratorIndicator: false, + + // Disables the reactions feature. + // disableReactions: true, + + // Disables the reactions moderation feature. + // disableReactionsModeration: false, + + // Disables the reactions in chat feature. + disableReactionsInChat: true, // This has been annoying =D + + // Disables polls feature. + // disablePolls: false, + + // Disables chat feature entirely including notifications, sounds, and private messages. + // disableChat: false, + + // Disables demote button from self-view + // disableSelfDemote: false, + + // Disables self-view tile. (hides it from tile view and from filmstrip) + // disableSelfView: false, + + // Disables self-view settings in UI + // disableSelfViewSettings: false, + + // screenshotCapture : { + // Enables the screensharing capture feature. + // enabled: false, + // + // The mode for the screenshot capture feature. + // Can be either 'recording' - screensharing screenshots are taken + // only when the recording is also on, + // or 'always' - screensharing screenshots are always taken. + // mode: 'recording', + // } + + // Disables ICE/UDP by filtering out local and remote UDP candidates in + // signalling. + // webrtcIceUdpDisable: false, + + // Disables ICE/TCP by filtering out local and remote TCP candidates in + // signalling. + // webrtcIceTcpDisable: false, + + + // Media + // + + // Audio + + // Disable measuring of audio levels. + disableAudioLevels: $(if [ -n "${DISABLE_AUDIO_LEVELS}" ]; then printf "true"; else printf "false"; fi), + + // audioLevelsInterval: 200, + + // Enabling this will run the lib-jitsi-meet no audio detection module which + // will notify the user if the current selected microphone has no audio + // input and will suggest another valid device if one is present. + enableNoAudioDetection: true, + + // Enabling this will show a "Save Logs" link in the GSM popover that can be + // used to collect debug information (XMPP IQs, SDP offer/answer cycles) + // about the call. + // enableSaveLogs: false, + + // Enabling this will hide the "Show More" link in the GSM popover that can be + // used to display more statistics about the connection (IP, Port, protocol, etc). + // disableShowMoreStats: true, + + // Enabling this will run the lib-jitsi-meet noise detection module which will + // notify the user if there is noise, other than voice, coming from the current + // selected microphone. The purpose it to let the user know that the input could + // be potentially unpleasant for other meeting participants. + enableNoisyMicDetection: true, + + // Start the conference in audio only mode (no video is being received nor + // sent). + // startAudioOnly: false, + + // Every participant after the Nth will start audio muted. + // startAudioMuted: 10, + + // Start calls with audio muted. Unlike the option above, this one is only + // applied locally. FIXME: having these 2 options is confusing. + // startWithAudioMuted: false, + + // Enabling it (with #params) will disable local audio output of remote + // participants and to enable it back a reload is needed. + // startSilent: false, + + // Enables support for opus-red (redundancy for Opus). + // enableOpusRed: false, + + // Specify audio quality stereo and opusMaxAverageBitrate values in order to enable HD audio. + // Beware, by doing so, you are disabling echo cancellation, noise suppression and AGC. + // Specify enableOpusDtx to enable support for opus-dtx where + // audio packets won’t be transmitted while participant is silent or muted. + // audioQuality: { + // stereo: false, + // opusMaxAverageBitrate: null, // Value to fit the 6000 to 510000 range. + // enableOpusDtx: false, + // }, + + // Noise suppression configuration. By default rnnoise is used. Optionally Krisp + // can be used by enabling it below, but the Krisp JS SDK files must be supplied in your + // installation. Specifically, these files are needed: + // - https://meet.example.com/libs/krisp/krisp.mjs + // - https://meet.example.com/libs/krisp/models/model_8.kw + // - https://meet.example.com/libs/krisp/models/model_nc.kw + // - https://meet.example.com/libs/krisp/models/model_bvc.kw + // - https://meet.example.com/libs/krisp/assets/bvc-allowed.txt + // In case when you have known BVC supported devices and you want to extend allowed devices list + // - https://meet.example.com/libs/krisp/assets/bvc-allowed-ext.txt + // In case when you have known BVC supported devices and you want to extend allowed devices list + // - https://meet.example.com/libs/krisp/models/model_inbound_8.kw + // - https://meet.example.com/libs/krisp/models/model_inbound_16.kw + // In case when you want to use inbound noise suppression models + // NOTE: Krisp JS SDK v2.0.0 was tested. + // noiseSuppression: { + // krisp: { + // enabled: false, + // logProcessStats: false, + // debugLogs: false, + // useBVC: false, + // bufferOverflowMS: 1000, + // inboundModels: { + // modelInbound8: 'model_inbound_8.kef', + // modelInbound16: 'model_inbound_16.kef', + // }, + // preloadInboundModels: { + // modelInbound8: 'model_inbound_8.kef', + // modelInbound16: 'model_inbound_16.kef', + // }, + // preloadModels: { + // modelBVC: 'model_bvc.kef', + // model8: 'model_8.kef', + // modelNC: 'model_nc_mq.kef', + // }, + // models: { + // modelBVC: 'model_bvc.kef', + // model8: 'model_8.kef', + // modelNV: 'model_nc_mq.kef', + // }, + // bvc: { + // allowedDevices: 'bvc-allowed.txt', + // allowedDevicesExt: 'bvc-allowed-ext.txt', + // } + // }, + // }, + + // Video + + // Sets the default camera facing mode. + // cameraFacingMode: 'user', + + // Sets the preferred resolution (height) for local video. Defaults to 720. + // resolution: 720, + + // DEPRECATED. Please use raisedHands.disableRemoveRaisedHandOnFocus instead. + // Specifies whether the raised hand will hide when someone becomes a dominant speaker or not + // disableRemoveRaisedHandOnFocus: false, + + // Specifies which raised hand related config should be set. + // raisedHands: { + // // Specifies whether the raised hand can be lowered by moderator. + // disableLowerHandByModerator: false, + + // // Specifies whether there is a notification before hiding the raised hand + // // when someone becomes the dominant speaker. + // disableLowerHandNotification: true, + + // // Specifies whether there is a notification when you are the next speaker in line. + // disableNextSpeakerNotification: false, + + // // Specifies whether the raised hand will hide when someone becomes a dominant speaker or not. + // disableRemoveRaisedHandOnFocus: false, + // }, + + // speakerStats: { + // // Specifies whether the speaker stats is enable or not. + // disabled: false, + + // // Specifies whether there will be a search field in speaker stats or not. + // disableSearch: false, + + // // Specifies whether participants in speaker stats should be ordered or not, and with what priority. + // // 'role', <- Moderators on top. + // // 'name', <- Alphabetically by name. + // // 'hasLeft', <- The ones that have left in the bottom. + // order: [ + // 'role', + // 'name', + // 'hasLeft', + // ], + // }, + + // DEPRECATED. Please use speakerStats.disableSearch instead. + // Specifies whether there will be a search field in speaker stats or not + // disableSpeakerStatsSearch: false, + + // DEPRECATED. Please use speakerStats.order . + // Specifies whether participants in speaker stats should be ordered or not, and with what priority + // speakerStatsOrder: [ + // 'role', <- Moderators on top + // 'name', <- Alphabetically by name + // 'hasLeft', <- The ones that have left in the bottom + // ], <- the order of the array elements determines priority + + // How many participants while in the tile view mode, before the receiving video quality is reduced from HD to SD. + // Use -1 to disable. + // maxFullResolutionParticipants: 2, + + // w3c spec-compliant video constraints to use for video capture. Currently + // used by browsers that return true from lib-jitsi-meet's + // util#browser#usesNewGumFlow. The constraints are independent from + // this config's resolution value. Defaults to requesting an ideal + // resolution of 720p. + // constraints: { + // video: { + // height: { + // ideal: 720, + // max: 720, + // min: 240, + // }, + // }, + // }, +$(if [ -n "${VIDEO_CONSTRAINTS}" ]; then echo "${VIDEO_CONSTRAINTS},"; fi) + + // Enable / disable simulcast support. + // disableSimulcast: false, + + // Every participant after the Nth will start video muted. + startVideoMuted: ${START_VIDEO_MUTED}, + + // Start calls with video muted. Unlike the option above, this one is only + // applied locally. FIXME: having these 2 options is confusing. + // startWithVideoMuted: false, + + // Desktop sharing + + // Optional desktop sharing frame rate options. Default value: min:5, max:5. + // Setting higher min/max values will affect the resolution, it makes it worse. + // desktopSharingFrameRate: { + // min: 5, + // max: 5, + // }, + + // Optional screenshare settings that give more control over screen capture in the browser. + // screenShareSettings: { + // // Show users the current tab is the preferred capture source, default: false. + // desktopPreferCurrentTab: false, + // // Allow users to select system audio, default: include. + // desktopSystemAudio: 'include', + // // Allow users to seamlessly switch which tab they are sharing without having to select the tab again. + // desktopSurfaceSwitching: 'include', + // // Allow a user to be shown a preference for what screen is to be captured, default: unset. + // desktopDisplaySurface: undefined, + // // Allow users to select the current tab as a capture source, default: exclude. + // desktopSelfBrowserSurface: 'exclude' + // }, + + // Recording + + // Enable the dropbox integration. + // dropbox: { + // appKey: '', // Specify your app key here. + // // A URL to redirect the user to, after authenticating + // // by default uses: + // // 'https://${DOMAIN}/static/oauth.html' + // redirectURI: + // 'https://${DOMAIN}/subfolder/static/oauth.html', + // }, + + // configuration for all things recording related. Existing settings will be migrated here in the future. + // recordings: { + // // IF true (default) recording audio and video is selected by default in the recording dialog. + // // recordAudioAndVideo: true, + // // If true, shows a notification at the start of the meeting with a call to action button + // // to start recording (for users who can do so). + // // suggestRecording: true, + // // If true, shows a warning label in the prejoin screen to point out the possibility that + // // the call you're joining might be recorded. + // // showPrejoinWarning: true, + // // If true, the notification for recording start will display a link to download the cloud recording. + // // showRecordingLink: true, + // // If true, mutes audio and video when a recording begins and displays a dialog + // // explaining the effect of unmuting. + // // requireConsent: true, + // // If true consent will be skipped for users who are already in the meeting. + // // skipConsentInMeeting: true, + // // Link for the recording consent dialog's "Learn more" link. + // // consentLearnMoreLink: 'https://jitsi.org/meet/consent', + // }, + + // recordingService: { + // // When integrations like dropbox are enabled only that will be shown, + // // by enabling fileRecordingsServiceEnabled, we show both the integrations + // // and the generic recording service (its configuration and storage type + // // depends on jibri configuration) + // enabled: false, + + // // Whether to show the possibility to share file recording with other people + // // (e.g. meeting participants), based on the actual implementation + // // on the backend. + // sharingEnabled: false, + + // // Hide the warning that says we only store the recording for 24 hours. + // hideStorageWarning: false, + // }, + + // DEPRECATED. Use recordingService.enabled instead. + // fileRecordingsServiceEnabled: false, + + // DEPRECATED. Use recordingService.sharingEnabled instead. + // fileRecordingsServiceSharingEnabled: false, + + // Local recording configuration. + // localRecording: { + // // Whether to disable local recording or not. + // disable: false, + + // // Whether to notify all participants when a participant is recording locally. + // notifyAllParticipants: false, + + // // Whether to disable the self recording feature (only local participant streams). + // disableSelfRecording: false, + // }, + + // Customize the Live Streaming dialog. Can be modified for a non-YouTube provider. + // liveStreaming: { + // // Whether to enable live streaming or not. + // enabled: false, + // // Terms link + // termsLink: 'https://www.youtube.com/t/terms', + // // Data privacy link + // dataPrivacyLink: 'https://policies.google.com/privacy', + // // RegExp string that validates the stream key input field + // validatorRegExpString: '^(?:[a-zA-Z0-9]{4}(?:-(?!$)|$)){4}', + // // Documentation reference for the live streaming feature. + // helpLink: 'https://jitsi.org/live' + // }, + + // DEPRECATED. Use liveStreaming.enabled instead. + // liveStreamingEnabled: false, + + // DEPRECATED. Use transcription.enabled instead. + // transcribingEnabled: false, + + // DEPRECATED. Use transcription.useAppLanguage instead. + // transcribeWithAppLanguage: true, + + // DEPRECATED. Use transcription.preferredLanguage instead. + // preferredTranscribeLanguage: 'en-US', + + // DEPRECATED. Use transcription.autoTranscribeOnRecord instead. + // autoCaptionOnRecord: false, + + // Transcription options. + // transcription: { + // // Whether the feature should be enabled or not. + // enabled: false, + + // // Translation languages. + // // Available languages can be found in + // // ./lang/translation-languages.json. + // translationLanguages: ['en', 'es', 'fr', 'ro'], + + // // Important languages to show on the top of the language list. + // translationLanguagesHead: ['en'], + + // // If true transcriber will use the application language. + // // The application language is either explicitly set by participants in their settings or automatically + // // detected based on the environment, e.g. if the app is opened in a chrome instance which + // // is using french as its default language then transcriptions for that participant will be in french. + // // Defaults to true. + // useAppLanguage: true, + + // // Transcriber language. This settings will only work if "useAppLanguage" + // // is explicitly set to false. + // // Available languages can be found in + // // ./src/react/features/transcribing/transcriber-langs.json. + // preferredLanguage: 'en-US', + + // // Enables automatic turning on transcribing when recording is started + // autoTranscribeOnRecord: false, + + // // Enables automatic request of subtitles when transcriber is present in the meeting, uses the default + // // language that is set + // autoCaptionOnTranscribe: false, + // + // // Disables everything related to closed captions - the tab in the chat area, the button in the menu, + // // subtitles on stage and the "Show subtitles on stage" checkbox in the settings. + // // Note: Starting transcriptions from the recording dialog will still work. + // disableClosedCaptions: false, + + // // Whether to invite jigasi when backend transcriptions are enabled (asyncTranscription is true in metadata). + // // By default, we invite it. + // inviteJigasiOnBackendTranscribing: true, + // }, + + // Misc + + // Default value for the channel "last N" attribute. -1 for unlimited. + channelLastN: ${CHANNEL_LAST_N}, + + // Connection indicators + // connectionIndicators: { + // autoHide: true, + // autoHideTimeout: 5000, + // disabled: false, + // disableDetails: false, + // inactiveDisabled: false + // }, + + // Provides a way for the lastN value to be controlled through the UI. + // When startLastN is present, conference starts with a last-n value of startLastN and channelLastN + // value will be used when the quality level is selected using "Manage Video Quality" slider. + // startLastN: 1, + + // Specify the settings for video quality optimizations on the client. + // videoQuality: { + // + // // Provides a way to set the codec preference on desktop based endpoints. + // codecPreferenceOrder: [ 'AV1', 'VP9', 'VP8', 'H264' ], + // + // // Provides a way to set the codec for screenshare. + // screenshareCodec: 'AV1', + // mobileScreenshareCodec: 'VP8', + // + // // Enables the adaptive mode in the client that will make runtime adjustments to selected codecs and received + // // videos for a better user experience. This mode will kick in only when CPU overuse is reported in the + // // WebRTC statistics for the outbound video streams. + // enableAdaptiveMode: false, + // + // // Codec specific settings for scalability modes and max bitrates. + // av1: { + // maxBitratesVideo: { + // low: 100000, + // standard: 300000, + // high: 1000000, + // fullHd: 2000000, + // ultraHd: 4000000, + // ssHigh: 2500000 + // }, + // scalabilityModeEnabled: true, + // useSimulcast: false, + // useKSVC: true + // }, + // h264: { + // maxBitratesVideo: { + // low: 200000, + // standard: 500000, + // high: 1500000, + // fullHd: 3000000, + // ultraHd: 6000000, + // ssHigh: 2500000 + // }, + // scalabilityModeEnabled: true + // }, + // vp8: { + // maxBitratesVideo: { + // low: 200000, + // standard: 500000, + // high: 1500000, + // fullHd: 3000000, + // ultraHd: 6000000, + // ssHigh: 2500000 + // }, + // scalabilityModeEnabled: false + // }, + // vp9: { + // maxBitratesVideo: { + // low: 100000, + // standard: 300000, + // high: 1200000, + // fullHd: 2500000, + // ultraHd: 5000000, + // ssHigh: 2500000 + // }, + // scalabilityModeEnabled: true, + // useSimulcast: false, + // useKSVC: true + // }, + // + // // The options can be used to override default thresholds of video thumbnail heights corresponding to + // // the video quality levels used in the application. At the time of this writing the allowed levels are: + // // 'low' - for the low quality level (180p at the time of this writing) + // // 'standard' - for the medium quality level (360p) + // // 'high' - for the high quality level (720p) + // // The keys should be positive numbers which represent the minimal thumbnail height for the quality level. + // // + // // With the default config value below the application will use 'low' quality until the thumbnails are + // // at least 360 pixels tall. If the thumbnail height reaches 720 pixels then the application will switch to + // // the high quality. + // minHeightForQualityLvl: { + // 360: 'standard', + // 720: 'high', + // }, + // + // // Provides a way to set the codec preference on mobile devices, both on RN and mobile browser based endpoint + // mobileCodecPreferenceOrder: [ 'VP8', 'VP9', 'H264', 'AV1' ], + // }, + + // Notification timeouts + // notificationTimeouts: { + // short: 2500, + // medium: 5000, + // long: 10000, + // extraLong: 60000, + // sticky: 0, + // }, + + // // Options for the recording limit notification. + // recordingLimit: { + // + // // The recording limit in minutes. Note: This number appears in the notification text + // // but doesn't enforce the actual recording time limit. This should be configured in + // // jibri! + // limit: 60, + // + // // The name of the app with unlimited recordings. + // appName: 'Unlimited recordings APP', + // + // // The URL of the app with unlimited recordings. + // appURL: 'https://unlimited.recordings.app.com/', + // }, + + // Disables or enables RTX (RFC 4588) (defaults to false). + // disableRtx: false, + + // Moves all Jitsi Meet 'beforeunload' logic (cleanup, leaving, disconnecting, etc) to the 'unload' event. + // disableBeforeUnloadHandlers: true, + + // Disables or enables TCC support in this client (default: enabled). + // enableTcc: true, + + // Disables or enables REMB support in this client (default: enabled). + // enableRemb: true, + + // Enables forced reload of the client when the call is migrated as a result of + // the bridge going down. + // enableForcedReload: true, + + // Use TURN/UDP servers for the jitsi-videobridge connection (by default + // we filter out TURN/UDP because it is usually not needed since the + // bridge itself is reachable via UDP) + // useTurnUdp: false + + // Enable support for encoded transform in supported browsers. This allows + // E2EE to work in Safari if the corresponding flag is enabled in the browser. + // Experimental. + // enableEncodedTransformSupport: false, + + // UI + // + + // Disables responsive tiles. + // disableResponsiveTiles: false, + + // DEPRECATED. Please use \`securityUi?.hideLobbyButton\` instead. + // Hides lobby button. + // hideLobbyButton: false, + + // DEPRECATED. Please use \`lobby?.autoKnock\` instead. + // If Lobby is enabled starts knocking automatically. + // autoKnockLobby: false, + + // DEPRECATED. Please use \`lobby?.enableChat\` instead. + // Enable lobby chat. + // enableLobbyChat: true, + + // DEPRECATED! Use \`breakoutRooms.hideAddRoomButton\` instead. + // Hides add breakout room button + // hideAddRoomButton: false, + + // Require users to always specify a display name. + // requireDisplayName: true, + + // Enables webhid functionality for Audio. + // enableWebHIDFeature: false, + + // DEPRECATED! Use 'welcomePage.disabled' instead. + // Whether to use a welcome page or not. In case it's false a random room + // will be joined when no room is specified. + // enableWelcomePage: true, + + // Configs for welcome page. + // welcomePage: { + // // Whether to disable welcome page. In case it's disabled a random room + // // will be joined when no room is specified. + // disabled: false, + // // If set, landing page will redirect to this URL. + // customUrl: '' + // }, + + // Configs for the lobby screen. + // lobby: { + // // If Lobby is enabled, it starts knocking automatically. Replaces \`autoKnockLobby\`. + // autoKnock: false, + // // Enables the lobby chat. Replaces \`enableLobbyChat\`. + // enableChat: true, + // // Shows the hangup button in the lobby screen. + // showHangUp: true, + // }, + + // Configs for the security related UI elements. + // securityUi: { + // // Hides the lobby button. Replaces \`hideLobbyButton\`. + // hideLobbyButton: false, + // // Hides the possibility to set and enter a lobby password. + // disableLobbyPassword: false, + // }, + + // Disable app shortcuts that are registered upon joining a conference + // disableShortcuts: false, + + // Disable initial browser getUserMedia requests. + // This is useful for scenarios where users might want to start a conference for screensharing only + // disableInitialGUM: false, + + // Enabling the close page will ignore the welcome page redirection when + // a call is hangup. + // enableClosePage: false, + + // Disable hiding of remote thumbnails when in a 1-on-1 conference call. + // Setting this to null, will also disable showing the remote videos + // when the toolbar is shown on mouse movements + // disable1On1Mode: null | false | true, + + // Default local name to be displayed + // defaultLocalDisplayName: 'me', + + // Default remote name to be displayed + // defaultRemoteDisplayName: 'Fellow Jitster', + + // Hides the display name from the participant thumbnail + // hideDisplayName: false, + + // Hides the dominant speaker name badge that hovers above the toolbox + // hideDominantSpeakerBadge: false, + + // Default language for the user interface. Cannot be overwritten. + // For iframe integrations, use the \`lang\` option directly instead. + defaultLanguage: '${DEFAULT_LANGUAGE}', + + // Disables profile and the edit of all fields from the profile settings (display name and email) + // disableProfile: false, + + // Hides the email section under profile settings. + // hideEmailInSettings: false, + + // When enabled the password used for locking a room is restricted to up to the number of digits specified + // default: roomPasswordNumberOfDigits: false, + // roomPasswordNumberOfDigits: 10, + + // Message to show the users. Example: 'The service will be down for + // maintenance at 01:00 AM GMT, + noticeMessage: '${NOTICE_MESSAGE}', + + // Enables calendar integration, depends on googleApiApplicationClientID + // and microsoftApiApplicationClientID + // enableCalendarIntegration: false, + + // Whether to notify when the conference is terminated because it was destroyed. + // notifyOnConferenceDestruction: true, + + // The client id for the google APIs used for the calendar integration, youtube livestreaming, etc. + // googleApiApplicationClientID: '', + + // Configs for prejoin page. + // prejoinConfig: { + // // When 'true', it shows an intermediate page before joining, where the user can configure their devices. + // enabled: true, + // // Hides the participant name editing field in the prejoin screen. + // // If requireDisplayName is also set as true, a name should still be provided through + // // either the jwt or the userInfo from the iframe api init object in order for this to have an effect. + // hideDisplayName: false, + // // List of buttons to hide from the extra join options dropdown. + // hideExtraJoinButtons: ['no-audio', 'by-phone'], + // // Configuration for pre-call test + // // By setting preCallTestEnabled, you enable the pre-call test in the prejoin page. + // // ICE server credentials need to be provided over the preCallTestICEUrl + // preCallTestEnabled: false, + // preCallTestICEUrl: '', + // // Shows the hangup button in the lobby screen. + // showHangUp: true, + // }, + + // When 'true', the user cannot edit the display name. + // (Mainly useful when used in conjunction with the JWT so the JWT name becomes read only.) + // readOnlyName: false, + + // If etherpad integration is enabled, setting this to true will + // automatically open the etherpad when a participant joins. This + // does not affect the mobile app since opening an etherpad + // obscures the conference controls -- it's better to let users + // choose to open the pad on their own in that case. + // openSharedDocumentOnJoin: false, + + // If true, shows the unsafe room name warning label when a room name is + // deemed unsafe (due to the simplicity in the name) and a password is not + // set or the lobby is not enabled. + // enableInsecureRoomNameWarning: false, + + // Array with avatar URL prefixes that need to use CORS. + // corsAvatarURLs: [ 'https://www.gravatar.com/avatar/' ], + + // Base URL for a Gravatar-compatible service. Defaults to Gravatar. + // DEPRECATED! Use \`gravatar.baseUrl\` instead. + // gravatarBaseURL: 'https://www.gravatar.com/avatar/', + + // Setup for Gravatar-compatible services. + // gravatar: { + // // Defaults to Gravatar. + // baseUrl: 'https://www.gravatar.com/avatar/', + // // True if Gravatar should be disabled. + // disabled: false, + // }, + + // App name to be displayed in the invitation email subject, as an alternative to + // interfaceConfig.APP_NAME. + // inviteAppName: null, + + // Moved from interfaceConfig(TOOLBAR_BUTTONS). + // The name of the toolbar buttons to display in the toolbar, including the + // "More actions" menu. If present, the button will display. Exceptions are + // "livestreaming" and "recording" which also require being a moderator and + // some other values in config.js to be enabled. Also, the "profile" button will + // not display for users with a JWT. + // Notes: + // - it's possible to reorder the buttons in the maintoolbar by changing the order of the mainToolbarButtons + // - 'desktop' controls the "Share your screen" button + // - if \`toolbarButtons\` is undefined, we fallback to enabling all buttons on the UI + // toolbarButtons: [ + // 'camera', + // 'chat', + // 'closedcaptions', + // 'desktop', + // 'download', + // 'embedmeeting', + // 'etherpad', + // 'feedback', + // 'filmstrip', + // 'fullscreen', + // 'hangup', + // 'help', + // 'highlight', + // 'invite', + // 'linktosalesforce', + // 'livestreaming', + // 'microphone', + // 'noisesuppression', + // 'participants-pane', + // 'profile', + // 'raisehand', + // 'recording', + // 'security', + // 'select-background', + // 'settings', + // 'shareaudio', + // 'sharedvideo', + // 'shortcuts', + // 'stats', + // 'tileview', + // 'toggle-camera', + // 'videoquality', + // 'whiteboard', + // ], + + // Holds values related to toolbar visibility control. + // toolbarConfig: { + // // Moved from interfaceConfig.INITIAL_TOOLBAR_TIMEOUT + // // The initial number of milliseconds for the toolbar buttons to be visible on screen. + // initialTimeout: 20000, + // // Moved from interfaceConfig.TOOLBAR_TIMEOUT + // // Number of milliseconds for the toolbar buttons to be visible on screen. + // timeout: 4000, + // // Moved from interfaceConfig.TOOLBAR_ALWAYS_VISIBLE + // // Whether toolbar should be always visible or should hide after x milliseconds. + // alwaysVisible: false, + // // Indicates whether the toolbar should still autohide when chat is open + // autoHideWhileChatIsOpen: false, + // // Default background color for the main toolbar. Accepts any valid CSS color. + // // backgroundColor: '#ffffff', + // }, + + // Overrides the buttons displayed in the main toolbar. Depending on the screen size the number of displayed + // buttons varies from 2 buttons to 8 buttons. Every array in the mainToolbarButtons array will replace the + // corresponding default buttons configuration matched by the number of buttons specified in the array. Arrays with + // more than 8 buttons or less then 2 buttons will be ignored. When there there isn't an override for a certain + // configuration (for example when 3 buttons are displayed) the default jitsi-meet configuration will be used. + // The order of the buttons in the array is preserved. + // mainToolbarButtons: [ + // [ 'microphone', 'camera', 'desktop', 'chat', 'raisehand', 'reactions', 'participants-pane', 'tileview' ], + // [ 'microphone', 'camera', 'desktop', 'chat', 'raisehand', 'participants-pane', 'tileview' ], + // [ 'microphone', 'camera', 'desktop', 'chat', 'raisehand', 'participants-pane' ], + // [ 'microphone', 'camera', 'desktop', 'chat', 'participants-pane' ], + // [ 'microphone', 'camera', 'chat', 'participants-pane' ], + // [ 'microphone', 'camera', 'chat' ], + // [ 'microphone', 'camera' ] + // ], + + // Toolbar buttons which have their click/tap event exposed through the API on + // \`toolbarButtonClicked\`. Passing a string for the button key will + // prevent execution of the click/tap routine; passing an object with \`key\` and + // \`preventExecution\` flag on false will not prevent execution of the click/tap + // routine. Below array with mixed mode for passing the buttons. + // buttonsWithNotifyClick: [ + // 'camera', + // { + // key: 'chat', + // preventExecution: false + // }, + // { + // key: 'closedcaptions', + // preventExecution: true + // }, + // 'desktop', + // 'download', + // 'embedmeeting', + // 'end-meeting', + // 'etherpad', + // 'feedback', + // 'filmstrip', + // 'fullscreen', + // 'hangup', + // 'hangup-menu', + // 'help', + // { + // key: 'invite', + // preventExecution: false + // }, + // 'livestreaming', + // 'microphone', + // 'mute-everyone', + // 'mute-video-everyone', + // 'noisesuppression', + // 'participants-pane', + // 'profile', + // { + // key: 'raisehand', + // preventExecution: true + // }, + // 'recording', + // 'security', + // 'select-background', + // 'settings', + // 'shareaudio', + // 'sharedvideo', + // 'shortcuts', + // 'stats', + // 'tileview', + // 'toggle-camera', + // 'videoquality', + // // The add passcode button from the security dialog. + // { + // key: 'add-passcode', + // preventExecution: false + // }, + // 'whiteboard', + // ], + + // Participant context menu buttons which have their click/tap event exposed through the API on + // \`participantMenuButtonClick\`. Passing a string for the button key will + // prevent execution of the click/tap routine; passing an object with \`key\` and + // \`preventExecution\` flag on false will not prevent execution of the click/tap + // routine. Below array with mixed mode for passing the buttons. + // participantMenuButtonsWithNotifyClick: [ + // 'allow-video', + // { + // key: 'ask-unmute', + // preventExecution: false + // }, + // 'conn-status', + // 'flip-local-video', + // 'grant-moderator', + // { + // key: 'kick', + // preventExecution: true + // }, + // { + // key: 'hide-self-view', + // preventExecution: false + // }, + // 'mute', + // 'mute-others', + // 'mute-others-video', + // 'mute-video', + // 'pinToStage', + // 'privateMessage', + // { + // key: 'remote-control', + // preventExecution: false + // }, + // 'send-participant-to-room', + // 'verify', + // ], + + // List of pre meeting screens buttons to hide. The values must be one or more of the 5 allowed buttons: + // 'microphone', 'camera', 'select-background', 'invite', 'settings' + // hiddenPremeetingButtons: [], + + // An array with custom option buttons for the participant context menu + // type: Array<{ icon: string; id: string; text: string; }> + // customParticipantMenuButtons: [], + + // An array with custom option buttons for the toolbar + // type: Array<{ icon: string; id: string; text: string; backgroundColor?: string; }> + // customToolbarButtons: [], + + // Stats + // + + // Whether to enable stats collection or not in the TraceablePeerConnection. + // This can be useful for debugging purposes (post-processing/analysis of + // the webrtc stats) as it is done in the jitsi-meet-torture bandwidth + // estimation tests. + // gatherStats: false, + + // The interval at which PeerConnection.getStats() is called. Defaults to 10000 + // pcStatsInterval: 10000, + + // Enables sending participants' display names to stats + // enableDisplayNameInStats: false, + + // Enables sending participants' emails (if available) to stats and other analytics + // enableEmailInStats: false, + + // faceLandmarks: { + // // Enables sharing your face coordinates. Used for centering faces within a video. + // enableFaceCentering: false, + + // // Enables detecting face expressions and sharing data with other participants + // enableFaceExpressionsDetection: false, + + // // Enables displaying face expressions in speaker stats + // enableDisplayFaceExpressions: false, + + // // Enable rtc stats for face landmarks + // enableRTCStats: false, + + // // Minimum required face movement percentage threshold for sending new face centering coordinates data. + // faceCenteringThreshold: 10, + + // // Milliseconds for processing a new image capture in order to detect face coordinates if they exist. + // captureInterval: 1000, + // }, + + // Controls the percentage of automatic feedback shown to participants. + // The default value is 100%. If set to 0, no automatic feedback will be requested + // feedbackPercentage: 100, + + // Privacy + // + + // If third party requests are disabled, no other server will be contacted. + // This means avatars will be locally generated and external stats integration + // will not function. + disableThirdPartyRequests: $(if [ -z "${ENABLE_THIRD_PARTY_REQUESTS}" ]; then printf "true"; else printf "false"; fi), + + + // Peer-To-Peer mode: used (if enabled) when there are just 2 participants. + // + + p2p: { + // Enables peer to peer mode. When enabled the system will try to + // establish a direct connection when there are exactly 2 participants + // in the room. If that succeeds the conference will stop sending data + // through the JVB and use the peer to peer connection instead. When a + // 3rd participant joins the conference will be moved back to the JVB + // connection. + enabled: true, + + // Sets the ICE transport policy for the p2p connection. At the time + // of this writing the list of possible values are 'all' and 'relay', + // but that is subject to change in the future. The enum is defined in + // the WebRTC standard: + // https://www.w3.org/TR/webrtc/#rtcicetransportpolicy-enum. + // If not set, the effective value is 'all'. + // iceTransportPolicy: 'all', + + // Provides a way to set the codec preference on mobile devices, both on RN and mobile browser based + // endpoints. + // mobileCodecPreferenceOrder: [ 'H264', 'VP8', 'VP9', 'AV1' ], + // + // Provides a way to set the codec preference on desktop based endpoints. + // codecPreferenceOrder: [ 'AV1', 'VP9', 'VP8', 'H264 ], + + // Provides a way to set the codec for screenshare. + // screenshareCodec: 'AV1', + // mobileScreenshareCodec: 'VP8', + + // How long we're going to wait, before going back to P2P after the 3rd + // participant has left the conference (to filter out page reload). + // backToP2PDelay: 5, + + // The STUN servers that will be used in the peer to peer connections + stunServers: [ + + // { urls: 'stun:jitsi-meet.example.com:3478' }, + { urls: 'stun:${TURN_SERVER}:443' }, + ], + }, + + analytics: { +${ANALYTICS_SETTINGS} + // True if the analytics should be disabled + // disabled: false, + + // Matomo configuration: + // matomoEndpoint: 'https://your-matomo-endpoint/', + // matomoSiteID: '42', + + // The Amplitude APP Key: + // amplitudeAPPKey: '', + + // Obfuscates room name sent to analytics (amplitude, rtcstats) + // Default value is false. + // obfuscateRoomName: false, + + // Configuration for the rtcstats server: + // By enabling rtcstats server every time a conference is joined the rtcstats + // module connects to the provided rtcstatsEndpoint and sends statistics regarding + // PeerConnection states along with getStats metrics polled at the specified + // interval. + // rtcstatsEnabled: false, + // rtcstatsStoreLogs: false, + + // In order to enable rtcstats one needs to provide a endpoint url. + // rtcstatsEndpoint: wss://rtcstats-server-pilot.jitsi.net/, + + // The interval at which rtcstats will poll getStats, defaults to 10000ms. + // If the value is set to 0 getStats won't be polled and the rtcstats client + // will only send data related to RTCPeerConnection events. + // rtcstatsPollInterval: 10000, + + // This determines if rtcstats sends the SDP to the rtcstats server or replaces + // all SDPs with an empty string instead. + // rtcstatsSendSdp: false, + + // Array of script URLs to load as lib-jitsi-meet "analytics handlers". + // scriptURLs: [ + // "https://example.com/my-custom-analytics.js", + // ], + + // By enabling watchRTCEnabled option you would want to use watchRTC feature + // This would also require to configure watchRTCConfigParams. + // Please remember to keep rtcstatsEnabled disabled for watchRTC to work. + // watchRTCEnabled: false, + }, + + // Logs that should go be passed through the 'log' event if a handler is defined for it + // apiLogLevels: ['warn', 'log', 'error', 'info', 'debug'], + + // Information about the jitsi-meet instance we are connecting to, including + // the user region as seen by the server. + // deploymentInfo: { + // shard: "shard1", + // region: "europe", + // userRegion: "asia", + // }, + + // Array of disabled sounds. + // Possible values: + // - 'ASKED_TO_UNMUTE_SOUND' + // - 'E2EE_OFF_SOUND' + // - 'E2EE_ON_SOUND' + // - 'INCOMING_MSG_SOUND' + // - 'KNOCKING_PARTICIPANT_SOUND' + // - 'LIVE_STREAMING_OFF_SOUND' + // - 'LIVE_STREAMING_ON_SOUND' + // - 'NO_AUDIO_SIGNAL_SOUND' + // - 'NOISY_AUDIO_INPUT_SOUND' + // - 'OUTGOING_CALL_EXPIRED_SOUND' + // - 'OUTGOING_CALL_REJECTED_SOUND' + // - 'OUTGOING_CALL_RINGING_SOUND' + // - 'OUTGOING_CALL_START_SOUND' + // - 'PARTICIPANT_JOINED_SOUND' + // - 'PARTICIPANT_LEFT_SOUND' + // - 'RAISE_HAND_SOUND' + // - 'REACTION_SOUND' + // - 'RECORDING_OFF_SOUND' + // - 'RECORDING_ON_SOUND' + // - 'TALK_WHILE_MUTED_SOUND' + disabledSounds: ['REACTION_SOUND'], // This is actually intrusive + + // DEPRECATED! Use \`disabledSounds\` instead. + // Decides whether the start/stop recording audio notifications should play on record. + // disableRecordAudioNotification: false, + + // DEPRECATED! Use \`disabledSounds\` instead. + // Disables the sounds that play when other participants join or leave the + // conference (if set to true, these sounds will not be played). + // disableJoinLeaveSounds: false, + + // DEPRECATED! Use \`disabledSounds\` instead. + // Disables the sounds that play when a chat message is received. + // disableIncomingMessageSound: false, + + // Information for the chrome extension banner + // chromeExtensionBanner: { + // // The chrome extension to be installed address + // url: 'https://chrome.google.com/webstore/detail/jitsi-meetings/kglhbbefdnlheedjiejgomgmfplipfeb', + // edgeUrl: 'https://microsoftedge.microsoft.com/addons/detail/jitsi-meetings/eeecajlpbgjppibfledfihobcabccihn', + + // // Extensions info which allows checking if they are installed or not + // chromeExtensionsInfo: [ + // { + // id: 'kglhbbefdnlheedjiejgomgmfplipfeb', + // path: 'jitsi-logo-48x48.png', + // }, + // // Edge extension info + // { + // id: 'eeecajlpbgjppibfledfihobcabccihn', + // path: 'jitsi-logo-48x48.png', + // }, + // ] + // }, + + // e2ee: { + // labels: { + // description: '', + // label: '', + // tooltip: '', + // warning: '', + // }, + // externallyManagedKey: false, + // disabled: false, + // }, + + // Options related to end-to-end (participant to participant) ping. + // e2eping: { + // // Whether ene-to-end pings should be enabled. + // enabled: false, + // + // // The number of responses to wait for. + // numRequests: 5, + // + // // The max conference size in which e2e pings will be sent. + // maxConferenceSize: 200, + // + // // The maximum number of e2e ping messages per second for the whole conference to aim for. + // // This is used to control the pacing of messages in order to reduce the load on the backend. + // maxMessagesPerSecond: 250, + // }, + + // If set, will attempt to use the provided video input device label when + // triggering a screenshare, instead of proceeding through the normal flow + // for obtaining a desktop stream. + // NOTE: This option is experimental and is currently intended for internal + // use only. + // _desktopSharingSourceDevice: 'sample-id-or-label', + + // DEPRECATED! Use deeplinking.disabled instead. + // If true, any checks to handoff to another application will be prevented + // and instead the app will continue to display in the current browser. + // disableDeepLinking: false, + + // The deeplinking config. + // deeplinking: { + // + // // The desktop deeplinking config, disabled by default. + // desktop: { + // appName: 'Jitsi Meet', + // appScheme: 'jitsi-meet, + // download: { + // linux: + // 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet-x86_64.AppImage', + // macos: 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet.dmg', + // windows: 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet.exe' + // }, + // enabled: false + // }, + // // If true, any checks to handoff to another application will be prevented + // // and instead the app will continue to display in the current browser. + // disabled: false, + + // // whether to hide the logo on the deep linking pages. + // hideLogo: false, + + // // The ios deeplinking config. + // ios: { + // appName: 'Jitsi Meet', + // // Specify mobile app scheme for opening the app from the mobile browser. + // appScheme: 'org.jitsi.meet', + // // Custom URL for downloading ios mobile app. + // downloadLink: 'https://itunes.apple.com/us/app/jitsi-meet/id1165103905', + // }, + + // // The android deeplinking config. + // android: { + // appName: 'Jitsi Meet', + // // Specify mobile app scheme for opening the app from the mobile browser. + // appScheme: 'org.jitsi.meet', + // // Custom URL for downloading android mobile app. + // downloadLink: 'https://play.google.com/store/apps/details?id=org.jitsi.meet', + // // Android app package name. + // appPackage: 'org.jitsi.meet', + // fDroidUrl: 'https://f-droid.org/en/packages/org.jitsi.meet/', + // } + // }, + + // // The terms, privacy and help centre URL's. + // // TODO: Check and set these up + legalUrls: { + helpCentre: '', + privacy: '', + terms: '' + // helpCentre: 'https://web-cdn.jitsi.net/faq/meet-faq.html', + // privacy: 'https://jitsi.org/meet/privacy', + // terms: 'https://jitsi.org/meet/terms' + }, + + // A property to disable the right click context menu for localVideo + // the menu has option to flip the locally seen video for local presentations + // disableLocalVideoFlip: false, + + // A property used to unset the default flip state of the local video. + // When it is set to 'true', the local(self) video will not be mirrored anymore. + // doNotFlipLocalVideo: false, + + // Mainly privacy related settings + + // Disables all invite functions from the app (share, invite, dial out...etc) + // disableInviteFunctions: true, + + // Disables storing the room name to the recents list. When in an iframe this is ignored and + // the room is never stored in the recents list. + // doNotStoreRoom: true, + + // Deployment specific URLs. + // deploymentUrls: { + // // If specified a 'Help' button will be displayed in the overflow menu with a link to the specified URL for + // // user documentation. + // userDocumentationURL: 'https://docs.example.com/video-meetings.html', + // // If specified a 'Download our apps' button will be displayed in the overflow menu with a link + // // to the specified URL for an app download page. + // downloadAppsUrl: 'https://docs.example.com/our-apps.html', + // }, + + // Options related to the remote participant menu. + // remoteVideoMenu: { + // // Whether the remote video context menu to be rendered or not. + // disabled: true, + // // If set to true the 'Switch to visitor' button will be disabled. + // disableDemote: true, + // // If set to true the 'Kick out' button will be disabled. + // disableKick: true, + // // If set to true the 'Grant moderator' button will be disabled. + // disableGrantModerator: true, + // // If set to 'all' the 'Private chat' button will be disabled for all participants. + // // If set to 'allow-moderator-chat' the 'Private chat' button will be available for chats with moderators. + // // If set to 'disable-visitor-chat' the 'Private chat' button will be disabled for visitor-main participant + // // conversations. + // disablePrivateChat: 'all' | 'allow-moderator-chat' | 'disable-visitor-chat', + // }, + + + // If set to true all muting operations of remote participants will be disabled. + // disableRemoteMute: true, + + /** + External API url used to receive branding specific information. + If there is no url set or there are missing fields, the defaults are applied. + The config file should be in JSON. + None of the fields are mandatory and the response must have the shape: + { + // Whether participant can only send group chat message if \`send-groupchat\` feature is enabled in jwt. + groupChatRequiresPermission: false, + // Whether participant can only create polls if \`create-polls\` feature is enabled in jwt. + pollCreationRequiresPermission: false, + // The domain url to apply (will replace the domain in the sharing conference link/embed section) + inviteDomain: 'example-company.org', + // The hex value for the colour used as background + backgroundColor: '#fff', + // The url for the image used as background + backgroundImageUrl: 'https://example.com/background-img.png', + // The anchor url used when clicking the logo image + logoClickUrl: 'https://example-company.org', + // The url used for the image used as logo + logoImageUrl: 'https://example.com/logo-img.png', + // Endpoint that enables support for salesforce integration with in-meeting resource linking + // This is required for: + // listing the most recent records - salesforceUrl/records/recents + // searching records - salesforceUrl/records?text=${text} + // retrieving record details - salesforceUrl/records/${id}?type=${type} + // and linking the meeting - salesforceUrl/sessions/${sessionId}/records/${id} + // salesforceUrl: 'https://api.example.com/', + // Overwrite for pool of background images for avatars + avatarBackgrounds: ['url(https://example.com/avatar-background-1.png)', '#FFF'], + // The lobby/prejoin screen background + premeetingBackground: 'url(https://example.com/premeeting-background.png)', + // A list of images that can be used as video backgrounds. + // When this field is present, the default images will be replaced with those provided. + virtualBackgrounds: ['https://example.com/img.jpg'], + // Object containing customized icons that should replace the default ones. + // The keys need to be the exact same icon names used in here: + // https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/icons/svg/index.ts + // To avoid having the icons trimmed or displayed in an unexpected way, please provide svg + // files containing svg xml icons in the size that the default icons come in. + customIcons: { + IconArrowUp: 'https://example.com/arrow-up.svg', + IconDownload: 'https://example.com/download.svg', + IconRemoteControlStart: 'https://example.com/remote-start.svg', + }, + // Object containing a theme's properties. It also supports partial overwrites of the main theme. + // For a list of all possible theme tokens and their current defaults, please check: + // https://github.com/jitsi/jitsi-meet/tree/master/resources/custom-theme/custom-theme.json + // For a short explanations on each of the tokens, please check: + // https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/ui/Tokens.ts + // IMPORTANT!: This is work in progress so many of the various tokens are not yet applied in code + // or they are partially applied. + customTheme: { + palette: { + ui01: "orange !important", + ui02: "maroon", + surface02: 'darkgreen', + ui03: "violet", + ui04: "magenta", + ui05: "blueviolet", + action01: 'green', + action01Hover: 'lightgreen', + disabled01: 'beige', + success02: 'cadetblue', + action02Hover: 'aliceblue', + }, + typography: { + labelRegular: { + fontSize: 25, + lineHeight: 30, + fontWeight: 500, + } + } + } + } + */ + dynamicBrandingUrl: "${DYNAMIC_BRANDING_URL}", + + // A list of allowed URL domains for shared video. + // + // NOTE: + // '*' is allowed value and it will allow any URL to be used for shared video. We do not recommend using '*', + // use it at your own risk! + // sharedVideoAllowedURLDomains: [ ], + + // Options related to the participants pane. + // participantsPane: { + // // Enables feature + // enabled: true, + // // Hides the moderator settings tab. + // hideModeratorSettingsTab: false, + // // Hides the more actions button. + // hideMoreActionsButton: false, + // // Hides the mute all button. + // hideMuteAllButton: false, + // }, + + // Options related to the breakout rooms feature. + // breakoutRooms: { + // // Hides the add breakout room button. This replaces \`hideAddRoomButton\`. + // hideAddRoomButton: false, + // // Hides the auto assign participants button. + // hideAutoAssignButton: false, + // // Hides the join breakout room button. + // hideJoinRoomButton: false, + // }, + + // When true, virtual background feature will be disabled. + // disableVirtualBackground: false, + + // When true the user cannot add more images to be used as virtual background. + // Only the default ones from will be available. + // disableAddingBackgroundImages: false, + + // Sets the background transparency level. '0' is fully transparent, '1' is opaque. + // backgroundAlpha: 1, + + // The URL of the moderated rooms microservice, if available. If it + // is present, a link to the service will be rendered on the welcome page, + // otherwise the app doesn't render it. + // moderatedRoomServiceUrl: 'https://moderated.jitsi-meet.example.com', + + // If true, tile view will not be enabled automatically when the participants count threshold is reached. + // disableTileView: true, + + // If true, the tiles will be displayed contained within the available space rather than enlarged to cover it, + // with a 16:9 aspect ratio (old behaviour). + // disableTileEnlargement: true, + + // Controls the visibility and behavior of the top header conference info labels. + // If a label's id is not in any of the 2 arrays, it will not be visible at all on the header. + // conferenceInfo: { + // // those labels will not be hidden in tandem with the toolbox. + // alwaysVisible: ['recording', 'raised-hands-count'], + // // those labels will be auto-hidden in tandem with the toolbox buttons. + // autoHide: [ + // 'subject', + // 'conference-timer', + // 'participants-count', + // 'e2ee', + // 'video-quality', + // 'insecure-room', + // 'highlight-moment', + // 'top-panel-toggle', + // ] + // }, + + // Hides the conference subject + // hideConferenceSubject: false, + + // Hides the conference timer. + // hideConferenceTimer: false, + + // Hides the recording label + // hideRecordingLabel: false, + + // Hides the participants stats + // hideParticipantsStats: true, + + // Sets the conference subject + // subject: 'Conference Subject', + + // Sets the conference local subject + // localSubject: 'Conference Local Subject', + + // This property is related to the use case when jitsi-meet is used via the IFrame API. When the property is true + // jitsi-meet will use the local storage of the host page instead of its own. This option is useful if the browser + // is not persisting the local storage inside the iframe. + // useHostPageLocalStorage: true, + + // Etherpad ("shared document") integration. + // + // If set, add a "Open shared document" link to the bottom right menu that + // will open an etherpad document. + // etherpad_base: 'https://your-etherpad-installati.on/p/', + + // To enable information about dial-in access to meetings you need to provide + // dialInNumbersUrl and dialInConfCodeUrl. + // dialInNumbersUrl returns a json array of numbers that can be used for dial-in. + // {"countryCode":"US","tollFree":false,"formattedNumber":"+1 123-456-7890"} + // dialInConfCodeUrl is the conference mapper converting a meeting id to a PIN used for dial-in + // or the other way around (more info in resources/cloud-api.swagger) + + // You can use external service for authentication that will redirect back passing a jwt token + // You can use tokenAuthUrl config to point to a URL of such service. + // The URL for the service supports few params which will be filled in by the code. + // tokenAuthUrl: + // 'https://myservice.com/auth/{room}?code_challenge_method=S256&code_challenge={code_challenge}&state={state}' + // Supported parameters in tokenAuthUrl: + // {room} - will be replaced with the room name + // {code_challenge} - (A web only). A oauth 2.0 code challenge that will be sent to the service. See: + // https://datatracker.ietf.org/doc/html/rfc7636. The code verifier will be saved in the sessionStorage + // under key: 'code_verifier'. + // {state} - A json with the current state before redirecting. Keys that are included in the state: + // - room (The current room name as shown in the address bar) + // - roomSafe (the backend safe room name to use (lowercase), that is passed to the backend) + // - tenant (The tenant if any) + // - config.xxx (all config overrides) + // - interfaceConfig.xxx (all interfaceConfig overrides) + // - ios=true (in case ios mobile app is used) + // - android=true (in case android mobile app is used) + // - electron=true (when web is loaded in electron app) + // If there is a logout service you can specify its URL with: + // tokenLogoutUrl: 'https://myservice.com/logout' + // You can enable tokenAuthUrlAutoRedirect which will detect that you have logged in successfully before + // and will automatically redirect to the token service to get the token for the meeting. + // tokenAuthUrlAutoRedirect: false + // An option to respect the context.tenant jwt field compared to the current tenant from the url + // tokenRespectTenant: false, + // An option to get for user info (name, picture, email) in the token outside the user context. + // Can be used with Firebase tokens. + // tokenGetUserInfoOutOfContext: false, + + // You can put an array of values to target different entity types in the invite dialog. + // Valid values are "phone", "room", "sip", "user", "videosipgw" and "email" + // peopleSearchQueryTypes: ["user", "email"], + // Directory endpoint which is called for invite dialog autocomplete + // peopleSearchUrl: "https://myservice.com/api/people", + // Endpoint which is called to send invitation requests + // inviteServiceUrl: "https://myservice.com/api/invite", + + // For external entities (e. g. email), the localStorage key holding the token value for directory authentication + // peopleSearchTokenLocation: "mytoken", + + + // Options related to visitors. + // visitors: { + // // Starts audio/video when the participant is promoted from visitor. + // enableMediaOnPromote: { + // audio: true, + // video: true + // }, + // // Hides the visitor count for visitors. + // // hideVisitorCountForVisitors: false, + // // Whether to show the join meeting dialog when joining as a visitor. + // // showJoinMeetingDialog: true, + // }, + // The default type of desktop sharing sources that will be used in the electron app. + // desktopSharingSources: ['screen', 'window'], + + // Disables the echo cancelation for local audio tracks. + // disableAEC: true, + + // Disables the auto gain control for local audio tracks. + // disableAGC: true, + + // Disables the audio processing (echo cancelation, auto gain control and noise suppression) for local audio tracks. + // disableAP: true, + + // Disables the anoise suppression for local audio tracks. + // disableNS: true, + + // Replaces the display name with the JID of the participants. + // displayJids: true, + + // Enables disables talk while muted detection. + // enableTalkWhileMuted: true, + + // Sets the peer connection ICE transport policy to "relay". + // forceTurnRelay: true, + + // List of undocumented settings used in jitsi-meet + /** + _immediateReloadThreshold + deploymentInfo + dialOutAuthUrl + dialOutCodesUrl + dialOutRegionUrl + disableRemoteControl + iAmRecorder + iAmSipGateway + microsoftApiApplicationClientID + */ + + /** + * This property can be used to alter the generated meeting invite links (in combination with a branding domain + * which is retrieved internally by jitsi meet) (e.g. https://meet.jit.si/someMeeting + * can become https://brandedDomain/roomAlias) + */ + // brandingRoomAlias: null, + + // List of undocumented settings used in lib-jitsi-meet + /** + _peerConnStatusOutOfLastNTimeout + _peerConnStatusRtcMuteTimeout + avgRtpStatsN + desktopSharingSources + disableLocalStats + hiddenDomain + hiddenFromRecorderFeatureEnabled + ignoreStartMuted + websocketKeepAlive + websocketKeepAliveUrl + */ + + /** + * Default interval (milliseconds) for triggering mouseMoved iframe API event + */ + mouseMoveCallbackInterval: 1000, + + /** + Use this array to configure which notifications will be shown to the user + The items correspond to the title or description key of that notification + Some of these notifications also depend on some other internal logic to be displayed or not, + so adding them here will not ensure they will always be displayed + + A falsy value for this prop will result in having all notifications enabled (e.g null, undefined, false) + */ + // notifications: [ + // 'connection.CONNFAIL', // shown when the connection fails, + // 'dialog.cameraConstraintFailedError', // shown when the camera failed + // 'dialog.cameraNotSendingData', // shown when there's no feed from user's camera + // 'dialog.kickTitle', // shown when user has been kicked + // 'dialog.liveStreaming', // livestreaming notifications (pending, on, off, limits) + // 'dialog.lockTitle', // shown when setting conference password fails + // 'dialog.maxUsersLimitReached', // shown when maximmum users limit has been reached + // 'dialog.micNotSendingData', // shown when user's mic is not sending any audio + // 'dialog.passwordNotSupportedTitle', // shown when setting conference password fails due to password format + // 'dialog.recording', // recording notifications (pending, on, off, limits) + // 'dialog.remoteControlTitle', // remote control notifications (allowed, denied, start, stop, error) + // 'dialog.reservationError', + // 'dialog.screenSharingFailedTitle', // shown when the screen sharing failed + // 'dialog.serviceUnavailable', // shown when server is not reachable + // 'dialog.sessTerminated', // shown when there is a failed conference session + // 'dialog.sessionRestarted', // show when a client reload is initiated because of bridge migration + // 'dialog.tokenAuthFailed', // show when an invalid jwt is used + // 'dialog.tokenAuthFailedWithReasons', // show when an invalid jwt is used with the reason behind the error + // 'dialog.transcribing', // transcribing notifications (pending, off) + // 'dialOut.statusMessage', // shown when dial out status is updated. + // 'liveStreaming.busy', // shown when livestreaming service is busy + // 'liveStreaming.failedToStart', // shown when livestreaming fails to start + // 'liveStreaming.unavailableTitle', // shown when livestreaming service is not reachable + // 'lobby.joinRejectedMessage', // shown when while in a lobby, user's request to join is rejected + // 'lobby.notificationTitle', // shown when lobby is toggled and when join requests are allowed / denied + // 'notify.audioUnmuteBlockedTitle', // shown when mic unmute blocked + // 'notify.chatMessages', // shown when receiving chat messages while the chat window is closed + // 'notify.connectedOneMember', // show when a participant joined + // 'notify.connectedThreePlusMembers', // show when more than 2 participants joined simultaneously + // 'notify.connectedTwoMembers', // show when two participants joined simultaneously + // 'notify.dataChannelClosed', // shown when the bridge channel has been disconnected + // 'notify.hostAskedUnmute', // shown to participant when host asks them to unmute + // 'notify.invitedOneMember', // shown when 1 participant has been invited + // 'notify.invitedThreePlusMembers', // shown when 3+ participants have been invited + // 'notify.invitedTwoMembers', // shown when 2 participants have been invited + // 'notify.kickParticipant', // shown when a participant is kicked + // 'notify.leftOneMember', // show when a participant left + // 'notify.leftThreePlusMembers', // show when more than 2 participants left simultaneously + // 'notify.leftTwoMembers', // show when two participants left simultaneously + // 'notify.linkToSalesforce', // shown when joining a meeting with salesforce integration + // 'notify.localRecordingStarted', // shown when the local recording has been started + // 'notify.localRecordingStopped', // shown when the local recording has been stopped + // 'notify.moderationInEffectCSTitle', // shown when user attempts to share content during AV moderation + // 'notify.moderationInEffectTitle', // shown when user attempts to unmute audio during AV moderation + // 'notify.moderationInEffectVideoTitle', // shown when user attempts to enable video during AV moderation + // 'notify.moderator', // shown when user gets moderator privilege + // 'notify.mutedRemotelyTitle', // shown when user is muted by a remote party + // 'notify.mutedTitle', // shown when user has been muted upon joining, + // 'notify.newDeviceAudioTitle', // prompts the user to use a newly detected audio device + // 'notify.newDeviceCameraTitle', // prompts the user to use a newly detected camera + // 'notify.noiseSuppressionFailedTitle', // shown when failed to start noise suppression + // 'notify.participantWantsToJoin', // shown when lobby is enabled and participant requests to join meeting + // 'notify.participantsWantToJoin', // shown when lobby is enabled and participants request to join meeting + // 'notify.passwordRemovedRemotely', // shown when a password has been removed remotely + // 'notify.passwordSetRemotely', // shown when a password has been set remotely + // 'notify.raisedHand', // shown when a participant used raise hand, + // 'notify.screenShareNoAudio', // shown when the audio could not be shared for the selected screen + // 'notify.screenSharingAudioOnlyTitle', // shown when the best performance has been affected by screen sharing + // 'notify.selfViewTitle', // show "You can always un-hide the self-view from settings" + // 'notify.startSilentTitle', // shown when user joined with no audio + // 'notify.suboptimalExperienceTitle', // show the browser warning + // 'notify.unmute', // shown to moderator when user raises hand during AV moderation + // 'notify.videoMutedRemotelyTitle', // shown when user's video is muted by a remote party, + // 'notify.videoUnmuteBlockedTitle', // shown when camera unmute and desktop sharing are blocked + // 'prejoin.errorDialOut', + // 'prejoin.errorDialOutDisconnected', + // 'prejoin.errorDialOutFailed', + // 'prejoin.errorDialOutStatus', + // 'prejoin.errorStatusCode', + // 'prejoin.errorValidation', + // 'recording.busy', // shown when recording service is busy + // 'recording.failedToStart', // shown when recording fails to start + // 'recording.unavailableTitle', // shown when recording service is not reachable + // 'toolbar.noAudioSignalTitle', // shown when a broken mic is detected + // 'toolbar.noisyAudioInputTitle', // shown when noise is detected for the current microphone + // 'toolbar.talkWhileMutedPopup', // shown when user tries to speak while muted + // 'transcribing.failed', // shown when transcribing fails + // ], + + // List of notifications to be disabled. Works in tandem with the above setting. + // disabledNotifications: [], + + // Prevent the filmstrip from autohiding when screen width is under a certain threshold + // disableFilmstripAutohiding: false, + + // filmstrip: { + // // Disable the vertical/horizontal filmstrip. + // disabled: false, + // // Disables user resizable filmstrip. Also, allows configuration of the filmstrip + // // (width, tiles aspect ratios) through the interfaceConfig options. + // disableResizable: false, + + // // Disables the stage filmstrip + // // (displaying multiple participants on stage besides the vertical filmstrip) + // disableStageFilmstrip: false, + + // // Default number of participants that can be displayed on stage. + // // The user can change this in settings. Number must be between 1 and 6. + // stageFilmstripParticipants: 1, + + // // Disables the top panel (only shown when a user is sharing their screen). + // disableTopPanel: false, + + // // The minimum number of participants that must be in the call for + // // the top panel layout to be used. + // minParticipantCountForTopPanel: 50, + + // // The width of the filmstrip on joining meeting. Can be resized afterwards. + // initialWidth: 400, + + // // Whether the draggable resize bar of the filmstrip is always visible. Setting this to true will make + // // the filmstrip always visible in case \`disableResizable\` is false. + // alwaysShowResizeBar: true, + // }, + + // Tile view related config options. + // tileView: { + // // Whether tileview should be disabled. + // disabled: false, + // // The optimal number of tiles that are going to be shown in tile view. Depending on the screen size it may + // // not be possible to show the exact number of participants specified here. + // numberOfVisibleTiles: 25, + // }, + + // Specifies whether the chat emoticons are disabled or not + // disableChatSmileys: false, + + // Settings for the GIPHY integration. + // giphy: { + // // Whether the feature is enabled or not. + // enabled: false, + // // SDK API Key from Giphy. + // sdkKey: '', + // // Display mode can be one of: + // // - tile: show the GIF on the tile of the participant that sent it. + // // - chat: show the GIF as a message in chat + // // - all: all of the above. This is the default option + // displayMode: 'all', + // // How long the GIF should be displayed on the tile (in milliseconds). + // tileTime: 5000, + // // Limit results by rating: g, pg, pg-13, r. Default value: g. + // rating: 'pg', + // }, + + // Logging + // logging: { + // // Default log level for the app and lib-jitsi-meet. + // defaultLogLevel: 'trace', + // // Option to disable LogCollector. + // //disableLogCollector: true, + // // Individual loggers are customizable. + // loggers: { + // // The following are too verbose in their logging with the default level. + // 'modules/RTC/TraceablePeerConnection.js': 'info', + // 'modules/xmpp/strophe.util.js': 'log', + // }, + // }, + + // Application logo url + // defaultLogoUrl: 'images/watermark.svg', + + // Settings for the Excalidraw whiteboard integration. + // whiteboard: { + // // Whether the feature is enabled or not. + // enabled: true, + // // The server used to support whiteboard collaboration. + // // https://github.com/jitsi/excalidraw-backend + // collabServerBaseUrl: 'https://excalidraw-backend.example.com', + // // The user access limit to the whiteboard, introduced as a means + // // to control the performance. + // userLimit: 25, + // // The url for more info about the whiteboard and its usage limitations. + // limitUrl: 'https://example.com/blog/whiteboard-limits', + // }, + + // The watchRTC initialize config params as described : + // https://testrtc.com/docs/installing-the-watchrtc-javascript-sdk/#h-set-up-the-sdk + // https://www.npmjs.com/package/@testrtc/watchrtc-sdk + // watchRTCConfigParams: { + // /** Watchrtc api key */ + // rtcApiKey: string; + // /** Identifier for the session */ + // rtcRoomId?: string; + // /** Identifier for the current peer */ + // rtcPeerId?: string; + // /** + // * ["tag1", "tag2", "tag3"] + // * @deprecated use 'keys' instead + // */ + // rtcTags?: string[]; + // /** { "key1": "value1", "key2": "value2"} */ + // keys?: any; + // /** Enables additional logging */ + // debug?: boolean; + // rtcToken?: string; + // /** + // * @deprecated No longer needed. Use "proxyUrl" instead. + // */ + // wsUrl?: string; + // proxyUrl?: string; + // console?: { + // level: string; + // override: boolean; + // }; + // allowBrowserLogCollection?: boolean; + // collectionInterval?: number; + // logGetStats?: boolean; + // }, + + // Hide login button on auth dialog, you may want to enable this if you are using JWT tokens to authenticate users + // hideLoginButton: true, + + // If true remove the tint foreground on focused user camera in filmstrip + // disableCameraTintForeground: false, + + // File sharign service. + // fileSharing: { + // // The URL of the file sharing service API. See resources/file-sharing.yaml for more details. + // apiUrl: 'https://example.com', + // // Whether the file sharing service is enabled or not. + // enabled: true, + // // Maximum file size limit (-1 value disables any file size limit check) + // maxFileSize: 50, + // }, +}; + +// Set the default values for JaaS customers +if (enableJaaS) { + config.dialInNumbersUrl = 'https://conference-mapper.jitsi.net/v1/access/dids'; + config.dialInConfCodeUrl = 'https://conference-mapper.jitsi.net/v1/access'; + config.roomPasswordNumberOfDigits = 10; // skip re-adding it (do not remove comment) +} +EOF +)" diff --git a/type/__jitsi_meet_domain/files/config.js.sh.orig b/type/__jitsi_meet_domain/files/config.js.sh.orig new file mode 100644 index 0000000..07c9095 --- /dev/null +++ b/type/__jitsi_meet_domain/files/config.js.sh.orig @@ -0,0 +1,1923 @@ +/* eslint-disable comma-dangle, no-unused-vars, no-var, prefer-template, vars-on-top */ + +/* + * NOTE: If you add a new option please remember to document it here: + * https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-configuration + */ + +var subdir = ''; +var subdomain = ''; + +if (subdomain) { + subdomain = subdomain.substr(0, subdomain.length - 1).split('.') + .join('_') + .toLowerCase() + '.'; +} + +// In case of no ssi provided by the webserver, use empty strings +if (subdir.startsWith('/' + subdir + 'conference-request/v1', + + // Options related to the bridge (colibri) data channel + bridgeChannel: { + // If the backend advertises multiple colibri websockets, this options allows + // to filter some of them out based on the domain name. We use the first URL + // which does not match ignoreDomain, falling back to the first one that matches + // ignoreDomain. Has no effect if undefined. + // ignoreDomain: 'example.com', + + // Prefer SCTP (WebRTC data channels over the media path) over a colibri websocket. + // If SCTP is available in the backend it will be used instead of a WS. Defaults to + // false (SCTP is used only if available and no WS are available). + // preferSctp: false + }, + + // Testing / experimental features. + // + + testing: { + // Allows the setting of a custom bandwidth value from the UI. + // assumeBandwidth: true, + + // Enables use of getDisplayMedia in electron + // electronUseGetDisplayMedia: false, + + // Enables AV1 codec for FF. Note: By default it is disabled. + // enableAV1ForFF: false, + + // Enables the use of the codec selection API supported by the browsers . + // enableCodecSelectionAPI: false, + + // P2P test mode disables automatic switching to P2P when there are 2 + // participants in the conference. + // p2pTestMode: false, + + // Enables the test specific features consumed by jitsi-meet-torture + // testMode: false, + + // Disables the auto-play behavior of *all* newly created video element. + // This is useful when the client runs on a host with limited resources. + // noAutoPlayVideo: false, + + // Experiment: Whether to skip interim transcriptions. + // skipInterimTranscriptions: false, + + // Dump transcripts to a element for debugging. + // dumpTranscript: false, + + // Log the audio levels. + // debugAudioLevels: true, + + // Will replace ice candidates IPs with invalid ones in order to fail ice. + // failICE: true, + + // When running on Spot TV, this controls whether to show the recording consent dialog. + // If false (default), Spot instances will not show the recording consent dialog. + // If true, Spot instances will show the recording consent dialog like regular clients. + // showSpotConsentDialog: false, + }, + + // Disables moderator indicators. + // disableModeratorIndicator: false, + + // Disables the reactions feature. + // disableReactions: true, + + // Disables the reactions moderation feature. + // disableReactionsModeration: false, + + // Disables the reactions in chat feature. + // disableReactionsInChat: false, + + // Disables polls feature. + // disablePolls: false, + + // Disables chat feature entirely including notifications, sounds, and private messages. + // disableChat: false, + + // Disables demote button from self-view + // disableSelfDemote: false, + + // Disables self-view tile. (hides it from tile view and from filmstrip) + // disableSelfView: false, + + // Disables self-view settings in UI + // disableSelfViewSettings: false, + + // screenshotCapture : { + // Enables the screensharing capture feature. + // enabled: false, + // + // The mode for the screenshot capture feature. + // Can be either 'recording' - screensharing screenshots are taken + // only when the recording is also on, + // or 'always' - screensharing screenshots are always taken. + // mode: 'recording', + // } + + // Disables ICE/UDP by filtering out local and remote UDP candidates in + // signalling. + // webrtcIceUdpDisable: false, + + // Disables ICE/TCP by filtering out local and remote TCP candidates in + // signalling. + // webrtcIceTcpDisable: false, + + + // Media + // + + // Audio + + // Disable measuring of audio levels. + // disableAudioLevels: false, + + // audioLevelsInterval: 200, + + // Enabling this will run the lib-jitsi-meet no audio detection module which + // will notify the user if the current selected microphone has no audio + // input and will suggest another valid device if one is present. + enableNoAudioDetection: true, + + // Enabling this will show a "Save Logs" link in the GSM popover that can be + // used to collect debug information (XMPP IQs, SDP offer/answer cycles) + // about the call. + // enableSaveLogs: false, + + // Enabling this will hide the "Show More" link in the GSM popover that can be + // used to display more statistics about the connection (IP, Port, protocol, etc). + // disableShowMoreStats: true, + + // Enabling this will run the lib-jitsi-meet noise detection module which will + // notify the user if there is noise, other than voice, coming from the current + // selected microphone. The purpose it to let the user know that the input could + // be potentially unpleasant for other meeting participants. + enableNoisyMicDetection: true, + + // Start the conference in audio only mode (no video is being received nor + // sent). + // startAudioOnly: false, + + // Every participant after the Nth will start audio muted. + // startAudioMuted: 10, + + // Start calls with audio muted. Unlike the option above, this one is only + // applied locally. FIXME: having these 2 options is confusing. + // startWithAudioMuted: false, + + // Enabling it (with #params) will disable local audio output of remote + // participants and to enable it back a reload is needed. + // startSilent: false, + + // Enables support for opus-red (redundancy for Opus). + // enableOpusRed: false, + + // Specify audio quality stereo and opusMaxAverageBitrate values in order to enable HD audio. + // Beware, by doing so, you are disabling echo cancellation, noise suppression and AGC. + // Specify enableOpusDtx to enable support for opus-dtx where + // audio packets won’t be transmitted while participant is silent or muted. + // audioQuality: { + // stereo: false, + // opusMaxAverageBitrate: null, // Value to fit the 6000 to 510000 range. + // enableOpusDtx: false, + // }, + + // Noise suppression configuration. By default rnnoise is used. Optionally Krisp + // can be used by enabling it below, but the Krisp JS SDK files must be supplied in your + // installation. Specifically, these files are needed: + // - https://meet.example.com/libs/krisp/krisp.mjs + // - https://meet.example.com/libs/krisp/models/model_8.kw + // - https://meet.example.com/libs/krisp/models/model_nc.kw + // - https://meet.example.com/libs/krisp/models/model_bvc.kw + // - https://meet.example.com/libs/krisp/assets/bvc-allowed.txt + // In case when you have known BVC supported devices and you want to extend allowed devices list + // - https://meet.example.com/libs/krisp/assets/bvc-allowed-ext.txt + // In case when you have known BVC supported devices and you want to extend allowed devices list + // - https://meet.example.com/libs/krisp/models/model_inbound_8.kw + // - https://meet.example.com/libs/krisp/models/model_inbound_16.kw + // In case when you want to use inbound noise suppression models + // NOTE: Krisp JS SDK v2.0.0 was tested. + // noiseSuppression: { + // krisp: { + // enabled: false, + // logProcessStats: false, + // debugLogs: false, + // useBVC: false, + // bufferOverflowMS: 1000, + // inboundModels: { + // modelInbound8: 'model_inbound_8.kef', + // modelInbound16: 'model_inbound_16.kef', + // }, + // preloadInboundModels: { + // modelInbound8: 'model_inbound_8.kef', + // modelInbound16: 'model_inbound_16.kef', + // }, + // preloadModels: { + // modelBVC: 'model_bvc.kef', + // model8: 'model_8.kef', + // modelNC: 'model_nc_mq.kef', + // }, + // models: { + // modelBVC: 'model_bvc.kef', + // model8: 'model_8.kef', + // modelNV: 'model_nc_mq.kef', + // }, + // bvc: { + // allowedDevices: 'bvc-allowed.txt', + // allowedDevicesExt: 'bvc-allowed-ext.txt', + // } + // }, + // }, + + // Video + + // Sets the default camera facing mode. + // cameraFacingMode: 'user', + + // Sets the preferred resolution (height) for local video. Defaults to 720. + // resolution: 720, + + // DEPRECATED. Please use raisedHands.disableRemoveRaisedHandOnFocus instead. + // Specifies whether the raised hand will hide when someone becomes a dominant speaker or not + // disableRemoveRaisedHandOnFocus: false, + + // Specifies which raised hand related config should be set. + // raisedHands: { + // // Specifies whether the raised hand can be lowered by moderator. + // disableLowerHandByModerator: false, + + // // Specifies whether there is a notification before hiding the raised hand + // // when someone becomes the dominant speaker. + // disableLowerHandNotification: true, + + // // Specifies whether there is a notification when you are the next speaker in line. + // disableNextSpeakerNotification: false, + + // // Specifies whether the raised hand will hide when someone becomes a dominant speaker or not. + // disableRemoveRaisedHandOnFocus: false, + // }, + + // speakerStats: { + // // Specifies whether the speaker stats is enable or not. + // disabled: false, + + // // Specifies whether there will be a search field in speaker stats or not. + // disableSearch: false, + + // // Specifies whether participants in speaker stats should be ordered or not, and with what priority. + // // 'role', <- Moderators on top. + // // 'name', <- Alphabetically by name. + // // 'hasLeft', <- The ones that have left in the bottom. + // order: [ + // 'role', + // 'name', + // 'hasLeft', + // ], + // }, + + // DEPRECATED. Please use speakerStats.disableSearch instead. + // Specifies whether there will be a search field in speaker stats or not + // disableSpeakerStatsSearch: false, + + // DEPRECATED. Please use speakerStats.order . + // Specifies whether participants in speaker stats should be ordered or not, and with what priority + // speakerStatsOrder: [ + // 'role', <- Moderators on top + // 'name', <- Alphabetically by name + // 'hasLeft', <- The ones that have left in the bottom + // ], <- the order of the array elements determines priority + + // How many participants while in the tile view mode, before the receiving video quality is reduced from HD to SD. + // Use -1 to disable. + // maxFullResolutionParticipants: 2, + + // w3c spec-compliant video constraints to use for video capture. Currently + // used by browsers that return true from lib-jitsi-meet's + // util#browser#usesNewGumFlow. The constraints are independent from + // this config's resolution value. Defaults to requesting an ideal + // resolution of 720p. + // constraints: { + // video: { + // height: { + // ideal: 720, + // max: 720, + // min: 240, + // }, + // }, + // }, + + // Enable / disable simulcast support. + // disableSimulcast: false, + + // Every participant after the Nth will start video muted. + // startVideoMuted: 10, + + // Start calls with video muted. Unlike the option above, this one is only + // applied locally. FIXME: having these 2 options is confusing. + // startWithVideoMuted: false, + + // Desktop sharing + + // Optional desktop sharing frame rate options. Default value: min:5, max:5. + // Setting higher min/max values will affect the resolution, it makes it worse. + // desktopSharingFrameRate: { + // min: 5, + // max: 5, + // }, + + // Optional screenshare settings that give more control over screen capture in the browser. + // screenShareSettings: { + // // Show users the current tab is the preferred capture source, default: false. + // desktopPreferCurrentTab: false, + // // Allow users to select system audio, default: include. + // desktopSystemAudio: 'include', + // // Allow users to seamlessly switch which tab they are sharing without having to select the tab again. + // desktopSurfaceSwitching: 'include', + // // Allow a user to be shown a preference for what screen is to be captured, default: unset. + // desktopDisplaySurface: undefined, + // // Allow users to select the current tab as a capture source, default: exclude. + // desktopSelfBrowserSurface: 'exclude' + // }, + + // Recording + + // Enable the dropbox integration. + // dropbox: { + // appKey: '', // Specify your app key here. + // // A URL to redirect the user to, after authenticating + // // by default uses: + // // 'https://jitsi-meet.example.com/static/oauth.html' + // redirectURI: + // 'https://jitsi-meet.example.com/subfolder/static/oauth.html', + // }, + + // configuration for all things recording related. Existing settings will be migrated here in the future. + // recordings: { + // // IF true (default) recording audio and video is selected by default in the recording dialog. + // // recordAudioAndVideo: true, + // // If true, shows a notification at the start of the meeting with a call to action button + // // to start recording (for users who can do so). + // // suggestRecording: true, + // // If true, shows a warning label in the prejoin screen to point out the possibility that + // // the call you're joining might be recorded. + // // showPrejoinWarning: true, + // // If true, the notification for recording start will display a link to download the cloud recording. + // // showRecordingLink: true, + // // If true, mutes audio and video when a recording begins and displays a dialog + // // explaining the effect of unmuting. + // // requireConsent: true, + // // If true consent will be skipped for users who are already in the meeting. + // // skipConsentInMeeting: true, + // // Link for the recording consent dialog's "Learn more" link. + // // consentLearnMoreLink: 'https://jitsi.org/meet/consent', + // }, + + // recordingService: { + // // When integrations like dropbox are enabled only that will be shown, + // // by enabling fileRecordingsServiceEnabled, we show both the integrations + // // and the generic recording service (its configuration and storage type + // // depends on jibri configuration) + // enabled: false, + + // // Whether to show the possibility to share file recording with other people + // // (e.g. meeting participants), based on the actual implementation + // // on the backend. + // sharingEnabled: false, + + // // Hide the warning that says we only store the recording for 24 hours. + // hideStorageWarning: false, + // }, + + // DEPRECATED. Use recordingService.enabled instead. + // fileRecordingsServiceEnabled: false, + + // DEPRECATED. Use recordingService.sharingEnabled instead. + // fileRecordingsServiceSharingEnabled: false, + + // Local recording configuration. + // localRecording: { + // // Whether to disable local recording or not. + // disable: false, + + // // Whether to notify all participants when a participant is recording locally. + // notifyAllParticipants: false, + + // // Whether to disable the self recording feature (only local participant streams). + // disableSelfRecording: false, + // }, + + // Customize the Live Streaming dialog. Can be modified for a non-YouTube provider. + // liveStreaming: { + // // Whether to enable live streaming or not. + // enabled: false, + // // Terms link + // termsLink: 'https://www.youtube.com/t/terms', + // // Data privacy link + // dataPrivacyLink: 'https://policies.google.com/privacy', + // // RegExp string that validates the stream key input field + // validatorRegExpString: '^(?:[a-zA-Z0-9]{4}(?:-(?!$)|$)){4}', + // // Documentation reference for the live streaming feature. + // helpLink: 'https://jitsi.org/live' + // }, + + // DEPRECATED. Use liveStreaming.enabled instead. + // liveStreamingEnabled: false, + + // DEPRECATED. Use transcription.enabled instead. + // transcribingEnabled: false, + + // DEPRECATED. Use transcription.useAppLanguage instead. + // transcribeWithAppLanguage: true, + + // DEPRECATED. Use transcription.preferredLanguage instead. + // preferredTranscribeLanguage: 'en-US', + + // DEPRECATED. Use transcription.autoTranscribeOnRecord instead. + // autoCaptionOnRecord: false, + + // Transcription options. + // transcription: { + // // Whether the feature should be enabled or not. + // enabled: false, + + // // Translation languages. + // // Available languages can be found in + // // ./lang/translation-languages.json. + // translationLanguages: ['en', 'es', 'fr', 'ro'], + + // // Important languages to show on the top of the language list. + // translationLanguagesHead: ['en'], + + // // If true transcriber will use the application language. + // // The application language is either explicitly set by participants in their settings or automatically + // // detected based on the environment, e.g. if the app is opened in a chrome instance which + // // is using french as its default language then transcriptions for that participant will be in french. + // // Defaults to true. + // useAppLanguage: true, + + // // Transcriber language. This settings will only work if "useAppLanguage" + // // is explicitly set to false. + // // Available languages can be found in + // // ./src/react/features/transcribing/transcriber-langs.json. + // preferredLanguage: 'en-US', + + // // Enables automatic turning on transcribing when recording is started + // autoTranscribeOnRecord: false, + + // // Enables automatic request of subtitles when transcriber is present in the meeting, uses the default + // // language that is set + // autoCaptionOnTranscribe: false, + // + // // Disables everything related to closed captions - the tab in the chat area, the button in the menu, + // // subtitles on stage and the "Show subtitles on stage" checkbox in the settings. + // // Note: Starting transcriptions from the recording dialog will still work. + // disableClosedCaptions: false, + + // // Whether to invite jigasi when backend transcriptions are enabled (asyncTranscription is true in metadata). + // // By default, we invite it. + // inviteJigasiOnBackendTranscribing: true, + // }, + + // Misc + + // Default value for the channel "last N" attribute. -1 for unlimited. + channelLastN: -1, + + // Connection indicators + // connectionIndicators: { + // autoHide: true, + // autoHideTimeout: 5000, + // disabled: false, + // disableDetails: false, + // inactiveDisabled: false + // }, + + // Provides a way for the lastN value to be controlled through the UI. + // When startLastN is present, conference starts with a last-n value of startLastN and channelLastN + // value will be used when the quality level is selected using "Manage Video Quality" slider. + // startLastN: 1, + + // Specify the settings for video quality optimizations on the client. + // videoQuality: { + // + // // Provides a way to set the codec preference on desktop based endpoints. + // codecPreferenceOrder: [ 'AV1', 'VP9', 'VP8', 'H264' ], + // + // // Provides a way to set the codec for screenshare. + // screenshareCodec: 'AV1', + // mobileScreenshareCodec: 'VP8', + // + // // Enables the adaptive mode in the client that will make runtime adjustments to selected codecs and received + // // videos for a better user experience. This mode will kick in only when CPU overuse is reported in the + // // WebRTC statistics for the outbound video streams. + // enableAdaptiveMode: false, + // + // // Codec specific settings for scalability modes and max bitrates. + // av1: { + // maxBitratesVideo: { + // low: 100000, + // standard: 300000, + // high: 1000000, + // fullHd: 2000000, + // ultraHd: 4000000, + // ssHigh: 2500000 + // }, + // scalabilityModeEnabled: true, + // useSimulcast: false, + // useKSVC: true + // }, + // h264: { + // maxBitratesVideo: { + // low: 200000, + // standard: 500000, + // high: 1500000, + // fullHd: 3000000, + // ultraHd: 6000000, + // ssHigh: 2500000 + // }, + // scalabilityModeEnabled: true + // }, + // vp8: { + // maxBitratesVideo: { + // low: 200000, + // standard: 500000, + // high: 1500000, + // fullHd: 3000000, + // ultraHd: 6000000, + // ssHigh: 2500000 + // }, + // scalabilityModeEnabled: false + // }, + // vp9: { + // maxBitratesVideo: { + // low: 100000, + // standard: 300000, + // high: 1200000, + // fullHd: 2500000, + // ultraHd: 5000000, + // ssHigh: 2500000 + // }, + // scalabilityModeEnabled: true, + // useSimulcast: false, + // useKSVC: true + // }, + // + // // The options can be used to override default thresholds of video thumbnail heights corresponding to + // // the video quality levels used in the application. At the time of this writing the allowed levels are: + // // 'low' - for the low quality level (180p at the time of this writing) + // // 'standard' - for the medium quality level (360p) + // // 'high' - for the high quality level (720p) + // // The keys should be positive numbers which represent the minimal thumbnail height for the quality level. + // // + // // With the default config value below the application will use 'low' quality until the thumbnails are + // // at least 360 pixels tall. If the thumbnail height reaches 720 pixels then the application will switch to + // // the high quality. + // minHeightForQualityLvl: { + // 360: 'standard', + // 720: 'high', + // }, + // + // // Provides a way to set the codec preference on mobile devices, both on RN and mobile browser based endpoint + // mobileCodecPreferenceOrder: [ 'VP8', 'VP9', 'H264', 'AV1' ], + // }, + + // Notification timeouts + // notificationTimeouts: { + // short: 2500, + // medium: 5000, + // long: 10000, + // extraLong: 60000, + // sticky: 0, + // }, + + // // Options for the recording limit notification. + // recordingLimit: { + // + // // The recording limit in minutes. Note: This number appears in the notification text + // // but doesn't enforce the actual recording time limit. This should be configured in + // // jibri! + // limit: 60, + // + // // The name of the app with unlimited recordings. + // appName: 'Unlimited recordings APP', + // + // // The URL of the app with unlimited recordings. + // appURL: 'https://unlimited.recordings.app.com/', + // }, + + // Disables or enables RTX (RFC 4588) (defaults to false). + // disableRtx: false, + + // Moves all Jitsi Meet 'beforeunload' logic (cleanup, leaving, disconnecting, etc) to the 'unload' event. + // disableBeforeUnloadHandlers: true, + + // Disables or enables TCC support in this client (default: enabled). + // enableTcc: true, + + // Disables or enables REMB support in this client (default: enabled). + // enableRemb: true, + + // Enables forced reload of the client when the call is migrated as a result of + // the bridge going down. + // enableForcedReload: true, + + // Use TURN/UDP servers for the jitsi-videobridge connection (by default + // we filter out TURN/UDP because it is usually not needed since the + // bridge itself is reachable via UDP) + // useTurnUdp: false + + // Enable support for encoded transform in supported browsers. This allows + // E2EE to work in Safari if the corresponding flag is enabled in the browser. + // Experimental. + // enableEncodedTransformSupport: false, + + // UI + // + + // Disables responsive tiles. + // disableResponsiveTiles: false, + + // DEPRECATED. Please use `securityUi?.hideLobbyButton` instead. + // Hides lobby button. + // hideLobbyButton: false, + + // DEPRECATED. Please use `lobby?.autoKnock` instead. + // If Lobby is enabled starts knocking automatically. + // autoKnockLobby: false, + + // DEPRECATED. Please use `lobby?.enableChat` instead. + // Enable lobby chat. + // enableLobbyChat: true, + + // DEPRECATED! Use `breakoutRooms.hideAddRoomButton` instead. + // Hides add breakout room button + // hideAddRoomButton: false, + + // Require users to always specify a display name. + // requireDisplayName: true, + + // Enables webhid functionality for Audio. + // enableWebHIDFeature: false, + + // DEPRECATED! Use 'welcomePage.disabled' instead. + // Whether to use a welcome page or not. In case it's false a random room + // will be joined when no room is specified. + // enableWelcomePage: true, + + // Configs for welcome page. + // welcomePage: { + // // Whether to disable welcome page. In case it's disabled a random room + // // will be joined when no room is specified. + // disabled: false, + // // If set, landing page will redirect to this URL. + // customUrl: '' + // }, + + // Configs for the lobby screen. + // lobby: { + // // If Lobby is enabled, it starts knocking automatically. Replaces `autoKnockLobby`. + // autoKnock: false, + // // Enables the lobby chat. Replaces `enableLobbyChat`. + // enableChat: true, + // // Shows the hangup button in the lobby screen. + // showHangUp: true, + // }, + + // Configs for the security related UI elements. + // securityUi: { + // // Hides the lobby button. Replaces `hideLobbyButton`. + // hideLobbyButton: false, + // // Hides the possibility to set and enter a lobby password. + // disableLobbyPassword: false, + // }, + + // Disable app shortcuts that are registered upon joining a conference + // disableShortcuts: false, + + // Disable initial browser getUserMedia requests. + // This is useful for scenarios where users might want to start a conference for screensharing only + // disableInitialGUM: false, + + // Enabling the close page will ignore the welcome page redirection when + // a call is hangup. + // enableClosePage: false, + + // Disable hiding of remote thumbnails when in a 1-on-1 conference call. + // Setting this to null, will also disable showing the remote videos + // when the toolbar is shown on mouse movements + // disable1On1Mode: null | false | true, + + // Default local name to be displayed + // defaultLocalDisplayName: 'me', + + // Default remote name to be displayed + // defaultRemoteDisplayName: 'Fellow Jitster', + + // Hides the display name from the participant thumbnail + // hideDisplayName: false, + + // Hides the dominant speaker name badge that hovers above the toolbox + // hideDominantSpeakerBadge: false, + + // Default language for the user interface. Cannot be overwritten. + // For iframe integrations, use the `lang` option directly instead. + // defaultLanguage: 'en', + + // Disables profile and the edit of all fields from the profile settings (display name and email) + // disableProfile: false, + + // Hides the email section under profile settings. + // hideEmailInSettings: false, + + // When enabled the password used for locking a room is restricted to up to the number of digits specified + // default: roomPasswordNumberOfDigits: false, + // roomPasswordNumberOfDigits: 10, + + // Message to show the users. Example: 'The service will be down for + // maintenance at 01:00 AM GMT, + // noticeMessage: '', + + // Enables calendar integration, depends on googleApiApplicationClientID + // and microsoftApiApplicationClientID + // enableCalendarIntegration: false, + + // Whether to notify when the conference is terminated because it was destroyed. + // notifyOnConferenceDestruction: true, + + // The client id for the google APIs used for the calendar integration, youtube livestreaming, etc. + // googleApiApplicationClientID: '', + + // Configs for prejoin page. + // prejoinConfig: { + // // When 'true', it shows an intermediate page before joining, where the user can configure their devices. + // enabled: true, + // // Hides the participant name editing field in the prejoin screen. + // // If requireDisplayName is also set as true, a name should still be provided through + // // either the jwt or the userInfo from the iframe api init object in order for this to have an effect. + // hideDisplayName: false, + // // List of buttons to hide from the extra join options dropdown. + // hideExtraJoinButtons: ['no-audio', 'by-phone'], + // // Configuration for pre-call test + // // By setting preCallTestEnabled, you enable the pre-call test in the prejoin page. + // // ICE server credentials need to be provided over the preCallTestICEUrl + // preCallTestEnabled: false, + // preCallTestICEUrl: '', + // // Shows the hangup button in the lobby screen. + // showHangUp: true, + // }, + + // When 'true', the user cannot edit the display name. + // (Mainly useful when used in conjunction with the JWT so the JWT name becomes read only.) + // readOnlyName: false, + + // If etherpad integration is enabled, setting this to true will + // automatically open the etherpad when a participant joins. This + // does not affect the mobile app since opening an etherpad + // obscures the conference controls -- it's better to let users + // choose to open the pad on their own in that case. + // openSharedDocumentOnJoin: false, + + // If true, shows the unsafe room name warning label when a room name is + // deemed unsafe (due to the simplicity in the name) and a password is not + // set or the lobby is not enabled. + // enableInsecureRoomNameWarning: false, + + // Array with avatar URL prefixes that need to use CORS. + // corsAvatarURLs: [ 'https://www.gravatar.com/avatar/' ], + + // Base URL for a Gravatar-compatible service. Defaults to Gravatar. + // DEPRECATED! Use `gravatar.baseUrl` instead. + // gravatarBaseURL: 'https://www.gravatar.com/avatar/', + + // Setup for Gravatar-compatible services. + // gravatar: { + // // Defaults to Gravatar. + // baseUrl: 'https://www.gravatar.com/avatar/', + // // True if Gravatar should be disabled. + // disabled: false, + // }, + + // App name to be displayed in the invitation email subject, as an alternative to + // interfaceConfig.APP_NAME. + // inviteAppName: null, + + // Moved from interfaceConfig(TOOLBAR_BUTTONS). + // The name of the toolbar buttons to display in the toolbar, including the + // "More actions" menu. If present, the button will display. Exceptions are + // "livestreaming" and "recording" which also require being a moderator and + // some other values in config.js to be enabled. Also, the "profile" button will + // not display for users with a JWT. + // Notes: + // - it's possible to reorder the buttons in the maintoolbar by changing the order of the mainToolbarButtons + // - 'desktop' controls the "Share your screen" button + // - if `toolbarButtons` is undefined, we fallback to enabling all buttons on the UI + // toolbarButtons: [ + // 'camera', + // 'chat', + // 'closedcaptions', + // 'desktop', + // 'download', + // 'embedmeeting', + // 'etherpad', + // 'feedback', + // 'filmstrip', + // 'fullscreen', + // 'hangup', + // 'help', + // 'highlight', + // 'invite', + // 'linktosalesforce', + // 'livestreaming', + // 'microphone', + // 'noisesuppression', + // 'participants-pane', + // 'profile', + // 'raisehand', + // 'recording', + // 'security', + // 'select-background', + // 'settings', + // 'shareaudio', + // 'sharedvideo', + // 'shortcuts', + // 'stats', + // 'tileview', + // 'toggle-camera', + // 'videoquality', + // 'whiteboard', + // ], + + // Holds values related to toolbar visibility control. + // toolbarConfig: { + // // Moved from interfaceConfig.INITIAL_TOOLBAR_TIMEOUT + // // The initial number of milliseconds for the toolbar buttons to be visible on screen. + // initialTimeout: 20000, + // // Moved from interfaceConfig.TOOLBAR_TIMEOUT + // // Number of milliseconds for the toolbar buttons to be visible on screen. + // timeout: 4000, + // // Moved from interfaceConfig.TOOLBAR_ALWAYS_VISIBLE + // // Whether toolbar should be always visible or should hide after x milliseconds. + // alwaysVisible: false, + // // Indicates whether the toolbar should still autohide when chat is open + // autoHideWhileChatIsOpen: false, + // // Default background color for the main toolbar. Accepts any valid CSS color. + // // backgroundColor: '#ffffff', + // }, + + // Overrides the buttons displayed in the main toolbar. Depending on the screen size the number of displayed + // buttons varies from 2 buttons to 8 buttons. Every array in the mainToolbarButtons array will replace the + // corresponding default buttons configuration matched by the number of buttons specified in the array. Arrays with + // more than 8 buttons or less then 2 buttons will be ignored. When there there isn't an override for a certain + // configuration (for example when 3 buttons are displayed) the default jitsi-meet configuration will be used. + // The order of the buttons in the array is preserved. + // mainToolbarButtons: [ + // [ 'microphone', 'camera', 'desktop', 'chat', 'raisehand', 'reactions', 'participants-pane', 'tileview' ], + // [ 'microphone', 'camera', 'desktop', 'chat', 'raisehand', 'participants-pane', 'tileview' ], + // [ 'microphone', 'camera', 'desktop', 'chat', 'raisehand', 'participants-pane' ], + // [ 'microphone', 'camera', 'desktop', 'chat', 'participants-pane' ], + // [ 'microphone', 'camera', 'chat', 'participants-pane' ], + // [ 'microphone', 'camera', 'chat' ], + // [ 'microphone', 'camera' ] + // ], + + // Toolbar buttons which have their click/tap event exposed through the API on + // `toolbarButtonClicked`. Passing a string for the button key will + // prevent execution of the click/tap routine; passing an object with `key` and + // `preventExecution` flag on false will not prevent execution of the click/tap + // routine. Below array with mixed mode for passing the buttons. + // buttonsWithNotifyClick: [ + // 'camera', + // { + // key: 'chat', + // preventExecution: false + // }, + // { + // key: 'closedcaptions', + // preventExecution: true + // }, + // 'desktop', + // 'download', + // 'embedmeeting', + // 'end-meeting', + // 'etherpad', + // 'feedback', + // 'filmstrip', + // 'fullscreen', + // 'hangup', + // 'hangup-menu', + // 'help', + // { + // key: 'invite', + // preventExecution: false + // }, + // 'livestreaming', + // 'microphone', + // 'mute-everyone', + // 'mute-video-everyone', + // 'noisesuppression', + // 'participants-pane', + // 'profile', + // { + // key: 'raisehand', + // preventExecution: true + // }, + // 'recording', + // 'security', + // 'select-background', + // 'settings', + // 'shareaudio', + // 'sharedvideo', + // 'shortcuts', + // 'stats', + // 'tileview', + // 'toggle-camera', + // 'videoquality', + // // The add passcode button from the security dialog. + // { + // key: 'add-passcode', + // preventExecution: false + // }, + // 'whiteboard', + // ], + + // Participant context menu buttons which have their click/tap event exposed through the API on + // `participantMenuButtonClick`. Passing a string for the button key will + // prevent execution of the click/tap routine; passing an object with `key` and + // `preventExecution` flag on false will not prevent execution of the click/tap + // routine. Below array with mixed mode for passing the buttons. + // participantMenuButtonsWithNotifyClick: [ + // 'allow-video', + // { + // key: 'ask-unmute', + // preventExecution: false + // }, + // 'conn-status', + // 'flip-local-video', + // 'grant-moderator', + // { + // key: 'kick', + // preventExecution: true + // }, + // { + // key: 'hide-self-view', + // preventExecution: false + // }, + // 'mute', + // 'mute-others', + // 'mute-others-video', + // 'mute-video', + // 'pinToStage', + // 'privateMessage', + // { + // key: 'remote-control', + // preventExecution: false + // }, + // 'send-participant-to-room', + // 'verify', + // ], + + // List of pre meeting screens buttons to hide. The values must be one or more of the 5 allowed buttons: + // 'microphone', 'camera', 'select-background', 'invite', 'settings' + // hiddenPremeetingButtons: [], + + // An array with custom option buttons for the participant context menu + // type: Array<{ icon: string; id: string; text: string; }> + // customParticipantMenuButtons: [], + + // An array with custom option buttons for the toolbar + // type: Array<{ icon: string; id: string; text: string; backgroundColor?: string; }> + // customToolbarButtons: [], + + // Stats + // + + // Whether to enable stats collection or not in the TraceablePeerConnection. + // This can be useful for debugging purposes (post-processing/analysis of + // the webrtc stats) as it is done in the jitsi-meet-torture bandwidth + // estimation tests. + // gatherStats: false, + + // The interval at which PeerConnection.getStats() is called. Defaults to 10000 + // pcStatsInterval: 10000, + + // Enables sending participants' display names to stats + // enableDisplayNameInStats: false, + + // Enables sending participants' emails (if available) to stats and other analytics + // enableEmailInStats: false, + + // faceLandmarks: { + // // Enables sharing your face coordinates. Used for centering faces within a video. + // enableFaceCentering: false, + + // // Enables detecting face expressions and sharing data with other participants + // enableFaceExpressionsDetection: false, + + // // Enables displaying face expressions in speaker stats + // enableDisplayFaceExpressions: false, + + // // Enable rtc stats for face landmarks + // enableRTCStats: false, + + // // Minimum required face movement percentage threshold for sending new face centering coordinates data. + // faceCenteringThreshold: 10, + + // // Milliseconds for processing a new image capture in order to detect face coordinates if they exist. + // captureInterval: 1000, + // }, + + // Controls the percentage of automatic feedback shown to participants. + // The default value is 100%. If set to 0, no automatic feedback will be requested + // feedbackPercentage: 100, + + // Privacy + // + + // If third party requests are disabled, no other server will be contacted. + // This means avatars will be locally generated and external stats integration + // will not function. + // disableThirdPartyRequests: false, + + + // Peer-To-Peer mode: used (if enabled) when there are just 2 participants. + // + + p2p: { + // Enables peer to peer mode. When enabled the system will try to + // establish a direct connection when there are exactly 2 participants + // in the room. If that succeeds the conference will stop sending data + // through the JVB and use the peer to peer connection instead. When a + // 3rd participant joins the conference will be moved back to the JVB + // connection. + enabled: true, + + // Sets the ICE transport policy for the p2p connection. At the time + // of this writing the list of possible values are 'all' and 'relay', + // but that is subject to change in the future. The enum is defined in + // the WebRTC standard: + // https://www.w3.org/TR/webrtc/#rtcicetransportpolicy-enum. + // If not set, the effective value is 'all'. + // iceTransportPolicy: 'all', + + // Provides a way to set the codec preference on mobile devices, both on RN and mobile browser based + // endpoints. + // mobileCodecPreferenceOrder: [ 'H264', 'VP8', 'VP9', 'AV1' ], + // + // Provides a way to set the codec preference on desktop based endpoints. + // codecPreferenceOrder: [ 'AV1', 'VP9', 'VP8', 'H264 ], + + // Provides a way to set the codec for screenshare. + // screenshareCodec: 'AV1', + // mobileScreenshareCodec: 'VP8', + + // How long we're going to wait, before going back to P2P after the 3rd + // participant has left the conference (to filter out page reload). + // backToP2PDelay: 5, + + // The STUN servers that will be used in the peer to peer connections + stunServers: [ + + // { urls: 'stun:jitsi-meet.example.com:3478' }, + { urls: 'stun:meet-jit-si-turnrelay.jitsi.net:443' }, + ], + }, + + analytics: { + // True if the analytics should be disabled + // disabled: false, + + // Matomo configuration: + // matomoEndpoint: 'https://your-matomo-endpoint/', + // matomoSiteID: '42', + + // The Amplitude APP Key: + // amplitudeAPPKey: '', + + // Obfuscates room name sent to analytics (amplitude, rtcstats) + // Default value is false. + // obfuscateRoomName: false, + + // Configuration for the rtcstats server: + // By enabling rtcstats server every time a conference is joined the rtcstats + // module connects to the provided rtcstatsEndpoint and sends statistics regarding + // PeerConnection states along with getStats metrics polled at the specified + // interval. + // rtcstatsEnabled: false, + // rtcstatsStoreLogs: false, + + // In order to enable rtcstats one needs to provide a endpoint url. + // rtcstatsEndpoint: wss://rtcstats-server-pilot.jitsi.net/, + + // The interval at which rtcstats will poll getStats, defaults to 10000ms. + // If the value is set to 0 getStats won't be polled and the rtcstats client + // will only send data related to RTCPeerConnection events. + // rtcstatsPollInterval: 10000, + + // This determines if rtcstats sends the SDP to the rtcstats server or replaces + // all SDPs with an empty string instead. + // rtcstatsSendSdp: false, + + // Array of script URLs to load as lib-jitsi-meet "analytics handlers". + // scriptURLs: [ + // "https://example.com/my-custom-analytics.js", + // ], + + // By enabling watchRTCEnabled option you would want to use watchRTC feature + // This would also require to configure watchRTCConfigParams. + // Please remember to keep rtcstatsEnabled disabled for watchRTC to work. + // watchRTCEnabled: false, + }, + + // Logs that should go be passed through the 'log' event if a handler is defined for it + // apiLogLevels: ['warn', 'log', 'error', 'info', 'debug'], + + // Information about the jitsi-meet instance we are connecting to, including + // the user region as seen by the server. + // deploymentInfo: { + // shard: "shard1", + // region: "europe", + // userRegion: "asia", + // }, + + // Array of disabled sounds. + // Possible values: + // - 'ASKED_TO_UNMUTE_SOUND' + // - 'E2EE_OFF_SOUND' + // - 'E2EE_ON_SOUND' + // - 'INCOMING_MSG_SOUND' + // - 'KNOCKING_PARTICIPANT_SOUND' + // - 'LIVE_STREAMING_OFF_SOUND' + // - 'LIVE_STREAMING_ON_SOUND' + // - 'NO_AUDIO_SIGNAL_SOUND' + // - 'NOISY_AUDIO_INPUT_SOUND' + // - 'OUTGOING_CALL_EXPIRED_SOUND' + // - 'OUTGOING_CALL_REJECTED_SOUND' + // - 'OUTGOING_CALL_RINGING_SOUND' + // - 'OUTGOING_CALL_START_SOUND' + // - 'PARTICIPANT_JOINED_SOUND' + // - 'PARTICIPANT_LEFT_SOUND' + // - 'RAISE_HAND_SOUND' + // - 'REACTION_SOUND' + // - 'RECORDING_OFF_SOUND' + // - 'RECORDING_ON_SOUND' + // - 'TALK_WHILE_MUTED_SOUND' + // disabledSounds: [], + + // DEPRECATED! Use `disabledSounds` instead. + // Decides whether the start/stop recording audio notifications should play on record. + // disableRecordAudioNotification: false, + + // DEPRECATED! Use `disabledSounds` instead. + // Disables the sounds that play when other participants join or leave the + // conference (if set to true, these sounds will not be played). + // disableJoinLeaveSounds: false, + + // DEPRECATED! Use `disabledSounds` instead. + // Disables the sounds that play when a chat message is received. + // disableIncomingMessageSound: false, + + // Information for the chrome extension banner + // chromeExtensionBanner: { + // // The chrome extension to be installed address + // url: 'https://chrome.google.com/webstore/detail/jitsi-meetings/kglhbbefdnlheedjiejgomgmfplipfeb', + // edgeUrl: 'https://microsoftedge.microsoft.com/addons/detail/jitsi-meetings/eeecajlpbgjppibfledfihobcabccihn', + + // // Extensions info which allows checking if they are installed or not + // chromeExtensionsInfo: [ + // { + // id: 'kglhbbefdnlheedjiejgomgmfplipfeb', + // path: 'jitsi-logo-48x48.png', + // }, + // // Edge extension info + // { + // id: 'eeecajlpbgjppibfledfihobcabccihn', + // path: 'jitsi-logo-48x48.png', + // }, + // ] + // }, + + // e2ee: { + // labels: { + // description: '', + // label: '', + // tooltip: '', + // warning: '', + // }, + // externallyManagedKey: false, + // disabled: false, + // }, + + // Options related to end-to-end (participant to participant) ping. + // e2eping: { + // // Whether ene-to-end pings should be enabled. + // enabled: false, + // + // // The number of responses to wait for. + // numRequests: 5, + // + // // The max conference size in which e2e pings will be sent. + // maxConferenceSize: 200, + // + // // The maximum number of e2e ping messages per second for the whole conference to aim for. + // // This is used to control the pacing of messages in order to reduce the load on the backend. + // maxMessagesPerSecond: 250, + // }, + + // If set, will attempt to use the provided video input device label when + // triggering a screenshare, instead of proceeding through the normal flow + // for obtaining a desktop stream. + // NOTE: This option is experimental and is currently intended for internal + // use only. + // _desktopSharingSourceDevice: 'sample-id-or-label', + + // DEPRECATED! Use deeplinking.disabled instead. + // If true, any checks to handoff to another application will be prevented + // and instead the app will continue to display in the current browser. + // disableDeepLinking: false, + + // The deeplinking config. + // deeplinking: { + // + // // The desktop deeplinking config, disabled by default. + // desktop: { + // appName: 'Jitsi Meet', + // appScheme: 'jitsi-meet, + // download: { + // linux: + // 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet-x86_64.AppImage', + // macos: 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet.dmg', + // windows: 'https://github.com/jitsi/jitsi-meet-electron/releases/latest/download/jitsi-meet.exe' + // }, + // enabled: false + // }, + // // If true, any checks to handoff to another application will be prevented + // // and instead the app will continue to display in the current browser. + // disabled: false, + + // // whether to hide the logo on the deep linking pages. + // hideLogo: false, + + // // The ios deeplinking config. + // ios: { + // appName: 'Jitsi Meet', + // // Specify mobile app scheme for opening the app from the mobile browser. + // appScheme: 'org.jitsi.meet', + // // Custom URL for downloading ios mobile app. + // downloadLink: 'https://itunes.apple.com/us/app/jitsi-meet/id1165103905', + // }, + + // // The android deeplinking config. + // android: { + // appName: 'Jitsi Meet', + // // Specify mobile app scheme for opening the app from the mobile browser. + // appScheme: 'org.jitsi.meet', + // // Custom URL for downloading android mobile app. + // downloadLink: 'https://play.google.com/store/apps/details?id=org.jitsi.meet', + // // Android app package name. + // appPackage: 'org.jitsi.meet', + // fDroidUrl: 'https://f-droid.org/en/packages/org.jitsi.meet/', + // } + // }, + + // // The terms, privacy and help centre URL's. + // legalUrls: { + // helpCentre: 'https://web-cdn.jitsi.net/faq/meet-faq.html', + // privacy: 'https://jitsi.org/meet/privacy', + // terms: 'https://jitsi.org/meet/terms' + // }, + + // A property to disable the right click context menu for localVideo + // the menu has option to flip the locally seen video for local presentations + // disableLocalVideoFlip: false, + + // A property used to unset the default flip state of the local video. + // When it is set to 'true', the local(self) video will not be mirrored anymore. + // doNotFlipLocalVideo: false, + + // Mainly privacy related settings + + // Disables all invite functions from the app (share, invite, dial out...etc) + // disableInviteFunctions: true, + + // Disables storing the room name to the recents list. When in an iframe this is ignored and + // the room is never stored in the recents list. + // doNotStoreRoom: true, + + // Deployment specific URLs. + // deploymentUrls: { + // // If specified a 'Help' button will be displayed in the overflow menu with a link to the specified URL for + // // user documentation. + // userDocumentationURL: 'https://docs.example.com/video-meetings.html', + // // If specified a 'Download our apps' button will be displayed in the overflow menu with a link + // // to the specified URL for an app download page. + // downloadAppsUrl: 'https://docs.example.com/our-apps.html', + // }, + + // Options related to the remote participant menu. + // remoteVideoMenu: { + // // Whether the remote video context menu to be rendered or not. + // disabled: true, + // // If set to true the 'Switch to visitor' button will be disabled. + // disableDemote: true, + // // If set to true the 'Kick out' button will be disabled. + // disableKick: true, + // // If set to true the 'Grant moderator' button will be disabled. + // disableGrantModerator: true, + // // If set to 'all' the 'Private chat' button will be disabled for all participants. + // // If set to 'allow-moderator-chat' the 'Private chat' button will be available for chats with moderators. + // // If set to 'disable-visitor-chat' the 'Private chat' button will be disabled for visitor-main participant + // // conversations. + // disablePrivateChat: 'all' | 'allow-moderator-chat' | 'disable-visitor-chat', + // }, + + + // If set to true all muting operations of remote participants will be disabled. + // disableRemoteMute: true, + + /** + External API url used to receive branding specific information. + If there is no url set or there are missing fields, the defaults are applied. + The config file should be in JSON. + None of the fields are mandatory and the response must have the shape: + { + // Whether participant can only send group chat message if `send-groupchat` feature is enabled in jwt. + groupChatRequiresPermission: false, + // Whether participant can only create polls if `create-polls` feature is enabled in jwt. + pollCreationRequiresPermission: false, + // The domain url to apply (will replace the domain in the sharing conference link/embed section) + inviteDomain: 'example-company.org', + // The hex value for the colour used as background + backgroundColor: '#fff', + // The url for the image used as background + backgroundImageUrl: 'https://example.com/background-img.png', + // The anchor url used when clicking the logo image + logoClickUrl: 'https://example-company.org', + // The url used for the image used as logo + logoImageUrl: 'https://example.com/logo-img.png', + // Endpoint that enables support for salesforce integration with in-meeting resource linking + // This is required for: + // listing the most recent records - salesforceUrl/records/recents + // searching records - salesforceUrl/records?text=${text} + // retrieving record details - salesforceUrl/records/${id}?type=${type} + // and linking the meeting - salesforceUrl/sessions/${sessionId}/records/${id} + // salesforceUrl: 'https://api.example.com/', + // Overwrite for pool of background images for avatars + avatarBackgrounds: ['url(https://example.com/avatar-background-1.png)', '#FFF'], + // The lobby/prejoin screen background + premeetingBackground: 'url(https://example.com/premeeting-background.png)', + // A list of images that can be used as video backgrounds. + // When this field is present, the default images will be replaced with those provided. + virtualBackgrounds: ['https://example.com/img.jpg'], + // Object containing customized icons that should replace the default ones. + // The keys need to be the exact same icon names used in here: + // https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/icons/svg/index.ts + // To avoid having the icons trimmed or displayed in an unexpected way, please provide svg + // files containing svg xml icons in the size that the default icons come in. + customIcons: { + IconArrowUp: 'https://example.com/arrow-up.svg', + IconDownload: 'https://example.com/download.svg', + IconRemoteControlStart: 'https://example.com/remote-start.svg', + }, + // Object containing a theme's properties. It also supports partial overwrites of the main theme. + // For a list of all possible theme tokens and their current defaults, please check: + // https://github.com/jitsi/jitsi-meet/tree/master/resources/custom-theme/custom-theme.json + // For a short explanations on each of the tokens, please check: + // https://github.com/jitsi/jitsi-meet/blob/master/react/features/base/ui/Tokens.ts + // IMPORTANT!: This is work in progress so many of the various tokens are not yet applied in code + // or they are partially applied. + customTheme: { + palette: { + ui01: "orange !important", + ui02: "maroon", + surface02: 'darkgreen', + ui03: "violet", + ui04: "magenta", + ui05: "blueviolet", + action01: 'green', + action01Hover: 'lightgreen', + disabled01: 'beige', + success02: 'cadetblue', + action02Hover: 'aliceblue', + }, + typography: { + labelRegular: { + fontSize: 25, + lineHeight: 30, + fontWeight: 500, + } + } + } + } + */ + // dynamicBrandingUrl: '', + + // A list of allowed URL domains for shared video. + // + // NOTE: + // '*' is allowed value and it will allow any URL to be used for shared video. We do not recommend using '*', + // use it at your own risk! + // sharedVideoAllowedURLDomains: [ ], + + // Options related to the participants pane. + // participantsPane: { + // // Enables feature + // enabled: true, + // // Hides the moderator settings tab. + // hideModeratorSettingsTab: false, + // // Hides the more actions button. + // hideMoreActionsButton: false, + // // Hides the mute all button. + // hideMuteAllButton: false, + // }, + + // Options related to the breakout rooms feature. + // breakoutRooms: { + // // Hides the add breakout room button. This replaces `hideAddRoomButton`. + // hideAddRoomButton: false, + // // Hides the auto assign participants button. + // hideAutoAssignButton: false, + // // Hides the join breakout room button. + // hideJoinRoomButton: false, + // }, + + // When true, virtual background feature will be disabled. + // disableVirtualBackground: false, + + // When true the user cannot add more images to be used as virtual background. + // Only the default ones from will be available. + // disableAddingBackgroundImages: false, + + // Sets the background transparency level. '0' is fully transparent, '1' is opaque. + // backgroundAlpha: 1, + + // The URL of the moderated rooms microservice, if available. If it + // is present, a link to the service will be rendered on the welcome page, + // otherwise the app doesn't render it. + // moderatedRoomServiceUrl: 'https://moderated.jitsi-meet.example.com', + + // If true, tile view will not be enabled automatically when the participants count threshold is reached. + // disableTileView: true, + + // If true, the tiles will be displayed contained within the available space rather than enlarged to cover it, + // with a 16:9 aspect ratio (old behaviour). + // disableTileEnlargement: true, + + // Controls the visibility and behavior of the top header conference info labels. + // If a label's id is not in any of the 2 arrays, it will not be visible at all on the header. + // conferenceInfo: { + // // those labels will not be hidden in tandem with the toolbox. + // alwaysVisible: ['recording', 'raised-hands-count'], + // // those labels will be auto-hidden in tandem with the toolbox buttons. + // autoHide: [ + // 'subject', + // 'conference-timer', + // 'participants-count', + // 'e2ee', + // 'video-quality', + // 'insecure-room', + // 'highlight-moment', + // 'top-panel-toggle', + // ] + // }, + + // Hides the conference subject + // hideConferenceSubject: false, + + // Hides the conference timer. + // hideConferenceTimer: false, + + // Hides the recording label + // hideRecordingLabel: false, + + // Hides the participants stats + // hideParticipantsStats: true, + + // Sets the conference subject + // subject: 'Conference Subject', + + // Sets the conference local subject + // localSubject: 'Conference Local Subject', + + // This property is related to the use case when jitsi-meet is used via the IFrame API. When the property is true + // jitsi-meet will use the local storage of the host page instead of its own. This option is useful if the browser + // is not persisting the local storage inside the iframe. + // useHostPageLocalStorage: true, + + // Etherpad ("shared document") integration. + // + // If set, add a "Open shared document" link to the bottom right menu that + // will open an etherpad document. + // etherpad_base: 'https://your-etherpad-installati.on/p/', + + // To enable information about dial-in access to meetings you need to provide + // dialInNumbersUrl and dialInConfCodeUrl. + // dialInNumbersUrl returns a json array of numbers that can be used for dial-in. + // {"countryCode":"US","tollFree":false,"formattedNumber":"+1 123-456-7890"} + // dialInConfCodeUrl is the conference mapper converting a meeting id to a PIN used for dial-in + // or the other way around (more info in resources/cloud-api.swagger) + + // You can use external service for authentication that will redirect back passing a jwt token + // You can use tokenAuthUrl config to point to a URL of such service. + // The URL for the service supports few params which will be filled in by the code. + // tokenAuthUrl: + // 'https://myservice.com/auth/{room}?code_challenge_method=S256&code_challenge={code_challenge}&state={state}' + // Supported parameters in tokenAuthUrl: + // {room} - will be replaced with the room name + // {code_challenge} - (A web only). A oauth 2.0 code challenge that will be sent to the service. See: + // https://datatracker.ietf.org/doc/html/rfc7636. The code verifier will be saved in the sessionStorage + // under key: 'code_verifier'. + // {state} - A json with the current state before redirecting. Keys that are included in the state: + // - room (The current room name as shown in the address bar) + // - roomSafe (the backend safe room name to use (lowercase), that is passed to the backend) + // - tenant (The tenant if any) + // - config.xxx (all config overrides) + // - interfaceConfig.xxx (all interfaceConfig overrides) + // - ios=true (in case ios mobile app is used) + // - android=true (in case android mobile app is used) + // - electron=true (when web is loaded in electron app) + // If there is a logout service you can specify its URL with: + // tokenLogoutUrl: 'https://myservice.com/logout' + // You can enable tokenAuthUrlAutoRedirect which will detect that you have logged in successfully before + // and will automatically redirect to the token service to get the token for the meeting. + // tokenAuthUrlAutoRedirect: false + // An option to respect the context.tenant jwt field compared to the current tenant from the url + // tokenRespectTenant: false, + // An option to get for user info (name, picture, email) in the token outside the user context. + // Can be used with Firebase tokens. + // tokenGetUserInfoOutOfContext: false, + + // You can put an array of values to target different entity types in the invite dialog. + // Valid values are "phone", "room", "sip", "user", "videosipgw" and "email" + // peopleSearchQueryTypes: ["user", "email"], + // Directory endpoint which is called for invite dialog autocomplete + // peopleSearchUrl: "https://myservice.com/api/people", + // Endpoint which is called to send invitation requests + // inviteServiceUrl: "https://myservice.com/api/invite", + + // For external entities (e. g. email), the localStorage key holding the token value for directory authentication + // peopleSearchTokenLocation: "mytoken", + + + // Options related to visitors. + // visitors: { + // // Starts audio/video when the participant is promoted from visitor. + // enableMediaOnPromote: { + // audio: true, + // video: true + // }, + // // Hides the visitor count for visitors. + // // hideVisitorCountForVisitors: false, + // // Whether to show the join meeting dialog when joining as a visitor. + // // showJoinMeetingDialog: true, + // }, + // The default type of desktop sharing sources that will be used in the electron app. + // desktopSharingSources: ['screen', 'window'], + + // Disables the echo cancelation for local audio tracks. + // disableAEC: true, + + // Disables the auto gain control for local audio tracks. + // disableAGC: true, + + // Disables the audio processing (echo cancelation, auto gain control and noise suppression) for local audio tracks. + // disableAP: true, + + // Disables the anoise suppression for local audio tracks. + // disableNS: true, + + // Replaces the display name with the JID of the participants. + // displayJids: true, + + // Enables disables talk while muted detection. + // enableTalkWhileMuted: true, + + // Sets the peer connection ICE transport policy to "relay". + // forceTurnRelay: true, + + // List of undocumented settings used in jitsi-meet + /** + _immediateReloadThreshold + deploymentInfo + dialOutAuthUrl + dialOutCodesUrl + dialOutRegionUrl + disableRemoteControl + iAmRecorder + iAmSipGateway + microsoftApiApplicationClientID + */ + + /** + * This property can be used to alter the generated meeting invite links (in combination with a branding domain + * which is retrieved internally by jitsi meet) (e.g. https://meet.jit.si/someMeeting + * can become https://brandedDomain/roomAlias) + */ + // brandingRoomAlias: null, + + // List of undocumented settings used in lib-jitsi-meet + /** + _peerConnStatusOutOfLastNTimeout + _peerConnStatusRtcMuteTimeout + avgRtpStatsN + desktopSharingSources + disableLocalStats + hiddenDomain + hiddenFromRecorderFeatureEnabled + ignoreStartMuted + websocketKeepAlive + websocketKeepAliveUrl + */ + + /** + * Default interval (milliseconds) for triggering mouseMoved iframe API event + */ + mouseMoveCallbackInterval: 1000, + + /** + Use this array to configure which notifications will be shown to the user + The items correspond to the title or description key of that notification + Some of these notifications also depend on some other internal logic to be displayed or not, + so adding them here will not ensure they will always be displayed + + A falsy value for this prop will result in having all notifications enabled (e.g null, undefined, false) + */ + // notifications: [ + // 'connection.CONNFAIL', // shown when the connection fails, + // 'dialog.cameraConstraintFailedError', // shown when the camera failed + // 'dialog.cameraNotSendingData', // shown when there's no feed from user's camera + // 'dialog.kickTitle', // shown when user has been kicked + // 'dialog.liveStreaming', // livestreaming notifications (pending, on, off, limits) + // 'dialog.lockTitle', // shown when setting conference password fails + // 'dialog.maxUsersLimitReached', // shown when maximmum users limit has been reached + // 'dialog.micNotSendingData', // shown when user's mic is not sending any audio + // 'dialog.passwordNotSupportedTitle', // shown when setting conference password fails due to password format + // 'dialog.recording', // recording notifications (pending, on, off, limits) + // 'dialog.remoteControlTitle', // remote control notifications (allowed, denied, start, stop, error) + // 'dialog.reservationError', + // 'dialog.screenSharingFailedTitle', // shown when the screen sharing failed + // 'dialog.serviceUnavailable', // shown when server is not reachable + // 'dialog.sessTerminated', // shown when there is a failed conference session + // 'dialog.sessionRestarted', // show when a client reload is initiated because of bridge migration + // 'dialog.tokenAuthFailed', // show when an invalid jwt is used + // 'dialog.tokenAuthFailedWithReasons', // show when an invalid jwt is used with the reason behind the error + // 'dialog.transcribing', // transcribing notifications (pending, off) + // 'dialOut.statusMessage', // shown when dial out status is updated. + // 'liveStreaming.busy', // shown when livestreaming service is busy + // 'liveStreaming.failedToStart', // shown when livestreaming fails to start + // 'liveStreaming.unavailableTitle', // shown when livestreaming service is not reachable + // 'lobby.joinRejectedMessage', // shown when while in a lobby, user's request to join is rejected + // 'lobby.notificationTitle', // shown when lobby is toggled and when join requests are allowed / denied + // 'notify.audioUnmuteBlockedTitle', // shown when mic unmute blocked + // 'notify.chatMessages', // shown when receiving chat messages while the chat window is closed + // 'notify.connectedOneMember', // show when a participant joined + // 'notify.connectedThreePlusMembers', // show when more than 2 participants joined simultaneously + // 'notify.connectedTwoMembers', // show when two participants joined simultaneously + // 'notify.dataChannelClosed', // shown when the bridge channel has been disconnected + // 'notify.hostAskedUnmute', // shown to participant when host asks them to unmute + // 'notify.invitedOneMember', // shown when 1 participant has been invited + // 'notify.invitedThreePlusMembers', // shown when 3+ participants have been invited + // 'notify.invitedTwoMembers', // shown when 2 participants have been invited + // 'notify.kickParticipant', // shown when a participant is kicked + // 'notify.leftOneMember', // show when a participant left + // 'notify.leftThreePlusMembers', // show when more than 2 participants left simultaneously + // 'notify.leftTwoMembers', // show when two participants left simultaneously + // 'notify.linkToSalesforce', // shown when joining a meeting with salesforce integration + // 'notify.localRecordingStarted', // shown when the local recording has been started + // 'notify.localRecordingStopped', // shown when the local recording has been stopped + // 'notify.moderationInEffectCSTitle', // shown when user attempts to share content during AV moderation + // 'notify.moderationInEffectTitle', // shown when user attempts to unmute audio during AV moderation + // 'notify.moderationInEffectVideoTitle', // shown when user attempts to enable video during AV moderation + // 'notify.moderator', // shown when user gets moderator privilege + // 'notify.mutedRemotelyTitle', // shown when user is muted by a remote party + // 'notify.mutedTitle', // shown when user has been muted upon joining, + // 'notify.newDeviceAudioTitle', // prompts the user to use a newly detected audio device + // 'notify.newDeviceCameraTitle', // prompts the user to use a newly detected camera + // 'notify.noiseSuppressionFailedTitle', // shown when failed to start noise suppression + // 'notify.participantWantsToJoin', // shown when lobby is enabled and participant requests to join meeting + // 'notify.participantsWantToJoin', // shown when lobby is enabled and participants request to join meeting + // 'notify.passwordRemovedRemotely', // shown when a password has been removed remotely + // 'notify.passwordSetRemotely', // shown when a password has been set remotely + // 'notify.raisedHand', // shown when a participant used raise hand, + // 'notify.screenShareNoAudio', // shown when the audio could not be shared for the selected screen + // 'notify.screenSharingAudioOnlyTitle', // shown when the best performance has been affected by screen sharing + // 'notify.selfViewTitle', // show "You can always un-hide the self-view from settings" + // 'notify.startSilentTitle', // shown when user joined with no audio + // 'notify.suboptimalExperienceTitle', // show the browser warning + // 'notify.unmute', // shown to moderator when user raises hand during AV moderation + // 'notify.videoMutedRemotelyTitle', // shown when user's video is muted by a remote party, + // 'notify.videoUnmuteBlockedTitle', // shown when camera unmute and desktop sharing are blocked + // 'prejoin.errorDialOut', + // 'prejoin.errorDialOutDisconnected', + // 'prejoin.errorDialOutFailed', + // 'prejoin.errorDialOutStatus', + // 'prejoin.errorStatusCode', + // 'prejoin.errorValidation', + // 'recording.busy', // shown when recording service is busy + // 'recording.failedToStart', // shown when recording fails to start + // 'recording.unavailableTitle', // shown when recording service is not reachable + // 'toolbar.noAudioSignalTitle', // shown when a broken mic is detected + // 'toolbar.noisyAudioInputTitle', // shown when noise is detected for the current microphone + // 'toolbar.talkWhileMutedPopup', // shown when user tries to speak while muted + // 'transcribing.failed', // shown when transcribing fails + // ], + + // List of notifications to be disabled. Works in tandem with the above setting. + // disabledNotifications: [], + + // Prevent the filmstrip from autohiding when screen width is under a certain threshold + // disableFilmstripAutohiding: false, + + // filmstrip: { + // // Disable the vertical/horizontal filmstrip. + // disabled: false, + // // Disables user resizable filmstrip. Also, allows configuration of the filmstrip + // // (width, tiles aspect ratios) through the interfaceConfig options. + // disableResizable: false, + + // // Disables the stage filmstrip + // // (displaying multiple participants on stage besides the vertical filmstrip) + // disableStageFilmstrip: false, + + // // Default number of participants that can be displayed on stage. + // // The user can change this in settings. Number must be between 1 and 6. + // stageFilmstripParticipants: 1, + + // // Disables the top panel (only shown when a user is sharing their screen). + // disableTopPanel: false, + + // // The minimum number of participants that must be in the call for + // // the top panel layout to be used. + // minParticipantCountForTopPanel: 50, + + // // The width of the filmstrip on joining meeting. Can be resized afterwards. + // initialWidth: 400, + + // // Whether the draggable resize bar of the filmstrip is always visible. Setting this to true will make + // // the filmstrip always visible in case `disableResizable` is false. + // alwaysShowResizeBar: true, + // }, + + // Tile view related config options. + // tileView: { + // // Whether tileview should be disabled. + // disabled: false, + // // The optimal number of tiles that are going to be shown in tile view. Depending on the screen size it may + // // not be possible to show the exact number of participants specified here. + // numberOfVisibleTiles: 25, + // }, + + // Specifies whether the chat emoticons are disabled or not + // disableChatSmileys: false, + + // Settings for the GIPHY integration. + // giphy: { + // // Whether the feature is enabled or not. + // enabled: false, + // // SDK API Key from Giphy. + // sdkKey: '', + // // Display mode can be one of: + // // - tile: show the GIF on the tile of the participant that sent it. + // // - chat: show the GIF as a message in chat + // // - all: all of the above. This is the default option + // displayMode: 'all', + // // How long the GIF should be displayed on the tile (in milliseconds). + // tileTime: 5000, + // // Limit results by rating: g, pg, pg-13, r. Default value: g. + // rating: 'pg', + // }, + + // Logging + // logging: { + // // Default log level for the app and lib-jitsi-meet. + // defaultLogLevel: 'trace', + // // Option to disable LogCollector. + // //disableLogCollector: true, + // // Individual loggers are customizable. + // loggers: { + // // The following are too verbose in their logging with the default level. + // 'modules/RTC/TraceablePeerConnection.js': 'info', + // 'modules/xmpp/strophe.util.js': 'log', + // }, + // }, + + // Application logo url + // defaultLogoUrl: 'images/watermark.svg', + + // Settings for the Excalidraw whiteboard integration. + // whiteboard: { + // // Whether the feature is enabled or not. + // enabled: true, + // // The server used to support whiteboard collaboration. + // // https://github.com/jitsi/excalidraw-backend + // collabServerBaseUrl: 'https://excalidraw-backend.example.com', + // // The user access limit to the whiteboard, introduced as a means + // // to control the performance. + // userLimit: 25, + // // The url for more info about the whiteboard and its usage limitations. + // limitUrl: 'https://example.com/blog/whiteboard-limits', + // }, + + // The watchRTC initialize config params as described : + // https://testrtc.com/docs/installing-the-watchrtc-javascript-sdk/#h-set-up-the-sdk + // https://www.npmjs.com/package/@testrtc/watchrtc-sdk + // watchRTCConfigParams: { + // /** Watchrtc api key */ + // rtcApiKey: string; + // /** Identifier for the session */ + // rtcRoomId?: string; + // /** Identifier for the current peer */ + // rtcPeerId?: string; + // /** + // * ["tag1", "tag2", "tag3"] + // * @deprecated use 'keys' instead + // */ + // rtcTags?: string[]; + // /** { "key1": "value1", "key2": "value2"} */ + // keys?: any; + // /** Enables additional logging */ + // debug?: boolean; + // rtcToken?: string; + // /** + // * @deprecated No longer needed. Use "proxyUrl" instead. + // */ + // wsUrl?: string; + // proxyUrl?: string; + // console?: { + // level: string; + // override: boolean; + // }; + // allowBrowserLogCollection?: boolean; + // collectionInterval?: number; + // logGetStats?: boolean; + // }, + + // Hide login button on auth dialog, you may want to enable this if you are using JWT tokens to authenticate users + // hideLoginButton: true, + + // If true remove the tint foreground on focused user camera in filmstrip + // disableCameraTintForeground: false, + + // File sharign service. + // fileSharing: { + // // The URL of the file sharing service API. See resources/file-sharing.yaml for more details. + // apiUrl: 'https://example.com', + // // Whether the file sharing service is enabled or not. + // enabled: true, + // // Maximum file size limit (-1 value disables any file size limit check) + // maxFileSize: 50, + // }, +}; + +// Set the default values for JaaS customers +if (enableJaaS) { + config.dialInNumbersUrl = 'https://conference-mapper.jitsi.net/v1/access/dids'; + config.dialInConfCodeUrl = 'https://conference-mapper.jitsi.net/v1/access'; + config.roomPasswordNumberOfDigits = 10; // skip re-adding it (do not remove comment) +} diff --git a/type/__jitsi_meet_domain/files/interface_config.js.sh b/type/__jitsi_meet_domain/files/interface_config.js.sh new file mode 100644 index 0000000..d2ebaa3 --- /dev/null +++ b/type/__jitsi_meet_domain/files/interface_config.js.sh @@ -0,0 +1,264 @@ +#!/bin/sh -e + +# default jitsi logo in svg +BRANDING_WATERMARK_PATH='images/watermark.svg' +# overrides default jitsi logo with the provided custom png logo +if [ -n "${BRANDING_WATERMARK}" ]; then + BRANDING_WATERMARK_PATH='images/watermark.png' +fi + +# shellcheck disable=SC2034 # This is intended to be included +JITSI_INTERFACE_CONFIG_JS="$(cat < + + +COPYING +------- +Copyright \(C) 2021 Evilham. diff --git a/type/__jitsi_meet_domain/manifest b/type/__jitsi_meet_domain/manifest new file mode 100755 index 0000000..755fe32 --- /dev/null +++ b/type/__jitsi_meet_domain/manifest @@ -0,0 +1,174 @@ +#!/bin/sh -e + +os="$(cat "${__global}/explorer/os")" +case "${os}" in + devuan|debian) + ;; + *) + echo "Your OS '${os}' is currently not supported." > /dev/stderr + exit 1 + ;; +esac + +DOMAIN="${__object_id}" +ADMIN_EMAIL="$(cat "${__object}/parameter/admin-email")" +CHANNEL_LAST_N="$(cat "${__object}/parameter/channel-last-n")" +DEFAULT_LANGUAGE="$(cat "${__object}/parameter/default-language")" +NOTICE_MESSAGE="$(cat "${__object}/parameter/notice-message")" +START_VIDEO_MUTED="$(cat "${__object}/parameter/start-video-muted")" +TURN_SERVER="$(cat "${__object}/parameter/turn-server")" +VIDEO_CONSTRAINTS="$(cat "${__object}/parameter/video-constraints")" +ANALYTICS_SETTINGS="$(cat "${__object}/parameter/analytics-settings")" +BRANDING_APP_NAME="$(cat "${__object}/parameter/branding-app-name")" +BRANDING_INDEX="$(cat "${__object}/parameter/branding-index")" +BRANDING_JSON="$(cat "${__object}/parameter/branding-json")" +BRANDING_WATERMARK="$(cat "${__object}/parameter/branding-watermark")" +STATE="$(cat "${__object}/parameter/state")" + +if [ "${BRANDING_INDEX}" = "-" ]; then + BRANDING_INDEX="${__object}/stdin" +fi + +if [ -f "${__object}/parameter/enable-third-party-requests" ]; then + ENABLE_THIRD_PARTY_REQUESTS="YES" +fi +if [ -f "${__object}/parameter/disable-audio-levels" ]; then + DISABLE_AUDIO_LEVELS="YES" +fi +if [ -f "${__object}/parameter/secured-domains" ]; then + SECURED_DOMAINS="YES" +fi + +if [ -z "${TURN_SERVER}" ]; then + TURN_SERVER="${__target_host}" +fi +if [ -z "${JITSI_HOST}" ]; then + JITSI_HOST="${__target_host}" +fi + +if [ -n "${BRANDING_JSON}" ]; then + DYNAMIC_BRANDING_URL="/branding.json" +fi + +case "${STATE}" in + present) + # When adding the domain, Let's Encrypt must come before nginx + le_require="" + nginx_require="__letsencrypt_cert/${DOMAIN}" + ;; + absent) + # When removing, nginx must come before Let's Encrypt + le_require="__file/etc/nginx/sites-enabled/${DOMAIN}.conf" + nginx_require="" + ;; + *) + cat >> /dev/stderr <<-EOM + Unsupported state '${STATE}', must be 'present' or 'absent'. + EOM + exit 1 + ;; +esac + +# +# Deal with certbot +# +# use object id as domain +require="${le_require}" __letsencrypt_cert "${DOMAIN}" \ + --state "${STATE}" \ + --admin-email "${ADMIN_EMAIL}" \ + --deploy-hook "service nginx reload" \ + --webroot /usr/share/jitsi-meet + +# Create virtualhost for nginx +# shellcheck source=type/__jitsi_meet_domain/files/nginx.sh +. "${__type}/files/nginx.sh" # This defines JITSI_NGINX_CONFIG +require="${nginx_require}" __file \ + "/etc/nginx/sites-enabled/${DOMAIN}.conf" \ + --state "${STATE}" \ + --mode 0644 --source "-" <@`. + +.. _RFC6122: https://xmpp.org/rfcs/rfc6122.html#nodeprep-prohibited + +To preserve idempotency we only allow lowercase for the users which correspond +to the `$__object_id` of this type. + +This type takes advantage of Prosody's plaintext authentication and managing a +file per user with the credentials. +If a different authentication mechanism is needed, `__jitsi_meet(7)` should be +patched accordingly. + +This type only works on De{bi,vu}an systems. + + +OPTIONAL PARAMETERS +------------------- +password + The user's password in plaintext. + Beware that since Prosody's plaintext authentication is used, this password + will also be stored as plaintext in the server. + Unless `--state` is `absent`, this parameter is required. + +state + Whether the user should be `present` (default) or `absent`. + +EXAMPLES +-------- + +.. code-block:: sh + + # Setup a Jitsi user for secure domain configuration + __jitsi_meet_user "user_1" --password "WeNeedGoodSecurity" + + # Remove such Jitsi user so it is not allowed to start meetings + __jitsi_meet_user "user_1" --state absent + + +SEE ALSO +-------- +- Prosody authentication https://modules.prosody.im/type_auth.html +- Jitsi Meet secure domain configuration https://jitsi.github.io/handbook/docs/devops-guide/secure-domain +- `__jitsi_meet(7)` +- `__jitsi_meet_domain(7)` + + +AUTHORS +------- +Pedro +Evilham + + +COPYING +------- +Copyright \(C) 2021 Pedro and Evilham. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__jitsi_meet_user/manifest b/type/__jitsi_meet_user/manifest new file mode 100755 index 0000000..826858f --- /dev/null +++ b/type/__jitsi_meet_user/manifest @@ -0,0 +1,37 @@ +#!/bin/sh -e + +basic_urlencode() { + echo "${1}" | sed 's/\./%2e/g' | sed 's/-/%2d/g' | sed 's/_/%5f/g' +} + +PASSWD="$(cat "${__object}/parameter/password" 2>/dev/null || true)" +STATE="$(cat "${__object}/parameter/state")" + +if [ -z "${PASSWD}" ] && [ "${STATE}" != "absent" ]; then + cat >> dev/stderr <<-EOF + A password is required unless you are removing the user '$__object_id'. + EOF +fi + +JITSI_USER_RAW="${__object_id}" +if echo "${JITSI_USER_RAW}" | grep -q ".*[A-Z\"&'/:<>@]"; then + cat > /dev/stderr <@) according to RFC6122. +EOF + exit 1 +fi + +JITSI_USER="$(basic_urlencode "${JITSI_USER_RAW}")" +FQDN="$(basic_urlencode "${__target_host}")" +FQDN_PATH="/var/lib/prosody/${FQDN}/accounts" +FILENAME="${FQDN_PATH}/${JITSI_USER}.dat" + +__directory "${FQDN_PATH}" --parents --owner prosody --group prosody --state "present" + +require="__directory${FQDN_PATH}" __file "${FILENAME}" --owner prosody --group prosody --mode 0440 \ + --state "${STATE}" --source - <&2 + Incompatible kernel version found - could not install jool kernel + modules. Please use one of linux-lts or linux-virt. + EOF + exit 1 +esac diff --git a/type/__jool/man.rst b/type/__jool/man.rst new file mode 100644 index 0000000..3220bc2 --- /dev/null +++ b/type/__jool/man.rst @@ -0,0 +1,69 @@ +cdist-type__jool(7) +=================== + +NAME +---- +cdist-type__jool - Configures a NAT64 instance using jool. + + +DESCRIPTION +----------- +This type configures an instance of a NAT64 using jool. This type **does not** +configure anything related to the other capacities of the jool project, such as +SIIT (see the `jool_siit` daemon / `__jool_siit` type - unimplemented at this +time). See https://jool.mx + +Note that this type is only implemented for the Alpine Linux operating system. + +Note that this type currently does not implement running several parallel +instances of jool NAT64. Please contribute your implementation if you do so. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +instance + The instance name, `default` if unspecified. + +framework + The used translation framework, `netfilter` if unspecified. + +pool6 + The IPv6 prefix used to map IPv4 addresses, `64:ff9b::/96` if unspecified. + + +EXAMPLES +-------- + +.. code-block:: sh + + __jool # Everything default + + # or, if you're feeling contrary + + __jool --instance "prettysoup" \ + --framework "iptables" \ + --pool6 "2001:DB8:dead:beef::/96" + + +SEE ALSO +-------- +`cdist-type__jool_siit(7)` - yet to be written +`cdist-type__joold(7)` - yet to be written + + +AUTHORS +------- +Joachim Desroches + + +COPYING +------- +Copyright \(C) 2021 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__jool/manifest b/type/__jool/manifest new file mode 100755 index 0000000..91a7f2c --- /dev/null +++ b/type/__jool/manifest @@ -0,0 +1,68 @@ +#!/bin/sh -e +# +# 2021 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + + +os=$(cat "${__global:?}/explorer/os") + +case "$os" in +'alpine') + packages="jool-tools jool-tools-openrc $(cat "${__object:?}"/explorer/alpine-kernel-modules)" + ;; +*) + printf "This type has no implementation for %s. Please contribute one if you can.\n" "$os" + exit 1 + ;; +esac + +for pkg in $packages; +do + __package "$pkg" +done + +instance="default" +if [ -f "${__object:?}/parameter/instance" ]; +then + instance="$(cat "${__object:?}/parameter/instance")" +fi + +framework="netfilter" +if [ -f "${__object:?}/parameter/framework" ]; +then + framework="$(cat "${__object:?}/parameter/framework")" +fi + +pool6="64:ff9b::/96" +if [ -f "${__object:?}/parameter/pool6" ]; +then + pool6="$(cat "${__object:?}/parameter/pool6")" +fi + +require='__package/jool-tools' __file /etc/jool/jool.conf \ + --source - <<- EOF + { + "instance": "$instance", + "framework": "$framework", + "global": { + "pool6": "$pool6" + } + } + EOF + +require='__package/jool-tools' __start_on_boot 'jool' diff --git a/type/__jool/parameter/optional b/type/__jool/parameter/optional new file mode 100644 index 0000000..822afd9 --- /dev/null +++ b/type/__jool/parameter/optional @@ -0,0 +1,3 @@ +instance +framework +pool6 diff --git a/type/__jool/singleton b/type/__jool/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__mail_alias/explorer/aliases b/type/__mail_alias/explorer/aliases new file mode 100755 index 0000000..ac13d7c --- /dev/null +++ b/type/__mail_alias/explorer/aliases @@ -0,0 +1,73 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# Find aliases for a given user name and print the aliases (each one on a +# separate line) + +aliases_file=$("${__type_explorer:?}/aliases_file") +test -r "${aliases_file}" || exit 0 + +: "${__object_id:?}" # assert __object_id is set, because it is used in AWK + +awk -F ':[ \t]*' ' +function print_aliases(aliases, matches) { + # prints comma-separated aliases (one per line) + split(aliases, matches, /,[ \t]*/) + for (i in matches) { + gsub(/^[ \t]*|[ \t]*$/, "", matches[i]) + if (matches[i]) print matches[i] + } +} + +/^#/ { + # comment line (ignore) + select = 0; cont = 0 # comments terminate alias lists and continuations + next +} + +{ + # is this line a continuation line? + # (the prev. line ended in a backslash or the line starts with whitespace) + is_cont = /^[ \t]/ || cont + + # detect if the line is a line to be continued (ends with a backslash) + cont = /\\$/ + + # if it is, we drop the backslash from the line + if (cont) sub(/[ \t]*\\$/, "", $0) +} + +is_cont { + # if in the alias list of the "target" user, we also print these aliases. + if (select) print_aliases($0) + next +} + +$1 == ENVIRON["__object_id"] { + # "target" user -> print alias list + select = 1 + print_aliases($2) + next +} + +{ + # other user + select = 0 +} +' "${aliases_file}" diff --git a/type/__mail_alias/explorer/aliases_file b/type/__mail_alias/explorer/aliases_file new file mode 100755 index 0000000..7f09f88 --- /dev/null +++ b/type/__mail_alias/explorer/aliases_file @@ -0,0 +1,52 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# This explorer finds the aliases file to modify. + +found() { echo "$*"; exit 0; } + +check_file() { + if test -f "$1" + then + found "$1" + fi +} + +case $("${__explorer:?}/os") +in + (freebsd|openbsd|solaris) + check_file /etc/mail/aliases + + # default + found /etc/mail/aliases + ;; + (alpine|debian|devuan|ubuntu) + check_file /etc/aliases + + # default + found /etc/aliases + ;; + (*) + check_file /etc/mail/aliases + check_file /etc/aliases + + # default + found /etc/aliases + ;; +esac diff --git a/type/__mail_alias/files/update_aliases.awk b/type/__mail_alias/files/update_aliases.awk new file mode 100644 index 0000000..11a4c85 --- /dev/null +++ b/type/__mail_alias/files/update_aliases.awk @@ -0,0 +1,96 @@ +#!/usr/bin/awk -f +# +# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +function getvalue(path, line) { + # Reads the first line of the file located at path and returns it. + getline line < path + close(path) + return line +} + +function sepafter(f, def, _) { + # finds the separator between field $f and $(f+1) + _ = substr($0, length($f)+1, index(substr($0, length($f)+1), $(f+1))-1) + return _ ? _ : def +} + +function write_aliases( line) { + if (aliases_written) return + + # print aliases line + printf "%s%s", ENVIRON["__object_id"], sepafter(1, ": ") + while ((getline line < aliases_should_file) > 0) { + if (aliases_written) printf ", " + printf "%s", line + aliases_written = 1 + } + printf "\n" + close(aliases_should_file) +} + +BEGIN { + FS = ":[ \t]*" + + parameter_dir = ENVIRON["__object"] "/parameter/" + + mode = (getvalue(parameter_dir "state") != "absent") + aliases_should_file = (parameter_dir "/alias") +} + +/^[ \t]*\#/ { + # comment line (leave alone) + select = 0; cont = 0 # comments terminate alias lists and continuations + print + next +} + +{ + # is this line a continuation line? + # (the prev. line ended in a backslash or the line starts with whitespace) + is_cont = /^[ \t]/ || cont + + # detect if the line is a line to be continued (ends with a backslash) + cont = /\\$/ +} + +is_cont { + # we only print the line if it has not been rewritten (select) + if (!select) print + next +} + +$1 == ENVIRON["__object_id"] { + # "target" user -> rewrite aliases list + select = 1 + if (mode) write_aliases() + next +} + +{ + # other user + select = 0 + print +} + +END { + # if the last line was an alias, the separator will be reused (looks better) + if (mode && !aliases_written) + write_aliases() +} diff --git a/type/__mail_alias/gencode-remote b/type/__mail_alias/gencode-remote new file mode 100755 index 0000000..4a8f889 --- /dev/null +++ b/type/__mail_alias/gencode-remote @@ -0,0 +1,87 @@ +#!/bin/sh -e +# +# 2020 Dennis Camera (dennis.camera@ssrq-sds-fds.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +quote() { printf "'%s'" "$(printf '%s' "$*" | sed -e "s/'/'\\\\''/g")"; } +drop_awk_comments() { quote "$(sed '/^[[:blank:]]*#.*$/d;/^$/d' "$@")"; } + +aliases_file=$(cat "${__object:?}/explorer/aliases_file") + +test -n "${aliases_file}" || { + echo 'Could not determine aliases file path.' >&2 + exit 1 +} + + +state_should=$(cat "${__object:?}/parameter/state") + +case ${state_should} +in + (present) + if cmp -s "${__object:?}/explorer/aliases" "${__object:?}/parameter/alias" + then + # all good! + exit 0 + fi + + test -s "${__object:?}/parameter/alias" || { + printf 'The --alias parameter is required if --state present.\n' >&2 + printf 'Use --state absent to remove all aliases.\n' >&2 + exit 1 + } + + if test -s "${__object:?}/explorer/aliases" + then + echo "update aliases" >>"${__messages_out:?}" + else + echo "add aliases" >>"${__messages_out:?}" + fi + ;; + (absent) + # nothing to do if no aliases found. + test -s "${__object:?}/explorer/aliases" || exit 0 + + echo "delete aliases" >>"${__messages_out:?}" + ;; + (*) + printf 'Invalid --state: %s.\n' "${state_should}" >&2 + printf 'Acceptable values are: present, absent.\n' >&2 + exit 1 +esac + +cat <$(quote "${aliases_file}.tmp") \ +|| { + rm -f $(quote "${aliases_file}.tmp") + echo 'Generating new aliases file failed!' >&2 + exit 1 +} + +if ! cmp -s $(quote "${aliases_file}") $(quote "${aliases_file}.tmp") +then + # aliases file was modified, replace: + cat $(quote "${aliases_file}.tmp") >$(quote "${aliases_file}") + + # then, run newaliases if present ("missing" on Alpine Linux because of typo) + command -v newaliases >/dev/null 2>&1 && newaliases || true +fi +rm -f $(quote "${aliases_file}.tmp") +EOF diff --git a/type/__mail_alias/man.rst b/type/__mail_alias/man.rst new file mode 100644 index 0000000..de40512 --- /dev/null +++ b/type/__mail_alias/man.rst @@ -0,0 +1,76 @@ +cdist-type__mail_alias(7) +========================= + +NAME +---- +cdist-type__mail_alias - Manage mail aliases. + + +DESCRIPTION +----------- +This cdist type allows you to configure mail aliases (/etc/aliases). + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +state + 'present' or 'absent', defaults to 'present' +alias + an alias, i.e. a mail address where mail for the user should be redirected + to. + This parameter can be specified multiple times to redirect to multiple + recipients. + If ``--state`` is ``present`` this parameter is required. + See `aliases(5)` for the different forms this parameter can take. + + +BOOLEAN PARAMETERS +------------------ +None. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Redirect root mail to a "real" email address + __mail_alias root --alias admin@example.com + + # Disable redirection of mail for joe + __mail_alias joe --state absent + + +BUGS +---- +- Quoted strings are not parsed by this type. As a result, aliases + containing ``,`` (commas) are treated incorrectly (they are treated as + separate aliases.) + Make sure that email addresses, file names, and pipe commands do not contain + commas. +- ``:include:`` directives in the aliases file are not evaluated by this type. + They are treated like a regular alias, the values of the included file are + not expanded. + + +SEE ALSO +-------- +:strong:`aliases`\ (5) + + +AUTHORS +------- +Dennis Camera + + +COPYING +------- +Copyright \(C) 2020 Dennis Camera. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__mail_alias/nonparallel b/type/__mail_alias/nonparallel new file mode 100644 index 0000000..e69de29 diff --git a/type/__mail_alias/parameter/default/state b/type/__mail_alias/parameter/default/state new file mode 100644 index 0000000..e7f6134 --- /dev/null +++ b/type/__mail_alias/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/type/__mail_alias/parameter/optional b/type/__mail_alias/parameter/optional new file mode 100644 index 0000000..ff72b5c --- /dev/null +++ b/type/__mail_alias/parameter/optional @@ -0,0 +1 @@ +state diff --git a/type/__mail_alias/parameter/optional_multiple b/type/__mail_alias/parameter/optional_multiple new file mode 100644 index 0000000..d077ed8 --- /dev/null +++ b/type/__mail_alias/parameter/optional_multiple @@ -0,0 +1 @@ +alias diff --git a/type/__matrix_element/files/config.json.sh b/type/__matrix_element/files/config.json.sh new file mode 100755 index 0000000..fa30cda --- /dev/null +++ b/type/__matrix_element/files/config.json.sh @@ -0,0 +1,94 @@ +#!/bin/sh +# +# Upstream configuration guide/documentation: +# https://github.com/vector-im/riot-web/blob/develop/docs/config.md + +generate_embedded_pages () { + if [ "$EMBED_HOMEPAGE" != "" ]; then + cat << EOF + "embeddedPages": { + "homeUrl": "home.html" + }, +EOF + fi +} + +generate_jitsi_config () { + if [ "$JITSI_DOMAIN" != "" ]; then + cat << EOF + "jitsi": { + "preferredDomain": "$JITSI_DOMAIN" + }, +EOF + fi +} + +generate_branding () { + echo '"branding": {' + + if [ "$BRANDING_AUTH_HEADER_LOGO_URL" != "" ]; then + cat << EOF + "authHeaderLogoUrl": "$BRANDING_AUTH_HEADER_LOGO_URL", +EOF + fi + + if [ "$BRANDING_AUTH_FOOTER_LINKS" != "" ]; then + cat << EOF + "authFooterLinks": $BRANDING_AUTH_FOOTER_LINKS, +EOF + fi + + cat << EOF + "welcomeBackgroundUrl": "$BRANDING_WELCOME_BACKGROUND_URL" +EOF + echo '},' +} + +cat << EOF +{ + "default_server_config": { + "m.homeserver": { + "base_url": "$DEFAULT_SERVER_URL", + "server_name": "$DEFAULT_SERVER_NAME" + }, + "m.identity_server": { + "base_url": "$IDENTITY_SERVER_URL" + } + }, + "brand": "$BRAND", + $(generate_branding) + "defaultCountryCode": "$DEFAULT_COUNTRY_CODE", + "integrations_ui_url": "https://scalar.vector.im/", + "integrations_rest_url": "https://scalar.vector.im/api", + "integrations_widgets_urls": [ + "https://scalar.vector.im/_matrix/integrations/v1", + "https://scalar.vector.im/api", + "https://scalar-staging.vector.im/_matrix/integrations/v1", + "https://scalar-staging.vector.im/api", + "https://scalar-staging.riot.im/scalar/api" + ], + "bug_report_endpoint_url": "https://riot.im/bugreports/submit", + "roomDirectory": { + "servers": [ + $ROOM_DIRECTORY_SERVERS + ] + }, + "disable_custom_urls": "$DISABLE_CUSTOM_URLS", + $(generate_embedded_pages) + $(generate_jitsi_config) + "terms_and_conditions_links": [ + { + "url": "$PRIVACY_POLICY_URL", + "text": "Privacy Policy" + }, + { + "url": "$COOKIE_POLICY_URL", + "text": "Cookie Policy" + } + ], + "embeddedPages": { + "welcomeUrl": "$WELCOME_PAGE_URL", + "homeUrl": "$HOME_PAGE_URL" + } +} +EOF diff --git a/type/__matrix_element/gencode-remote b/type/__matrix_element/gencode-remote new file mode 100755 index 0000000..ff3bbaa --- /dev/null +++ b/type/__matrix_element/gencode-remote @@ -0,0 +1,95 @@ +#!/bin/sh -e +# +# 2019 Timothée Floure (timothee.floure@ungleich.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# Function to compare version strings. Returns success (0) if the version +# given by stdin is higher than the version provided by the argument. +# +# Taken from the cdist core type __sensible_editor. +version_ge() { + awk -F '[^0-9.]' -v target="${1:?}" ' + function max(x, y) { return x > y ? x : y; } + BEGIN { + getline; + nx = split($1, x, "."); + ny = split(target, y, "."); + for (i = 1; i <= max(nx, ny); ++i) { + diff = int(x[i]) - int(y[i]); + if (diff < 0) exit 1; + else if (diff > 0) exit 0; + else continue; + } + }' +} + + +VERSION=$(cat "$__object/parameter/version") +INSTALL_DIR=$(cat "$__object/parameter/install_dir") +OWNER=$(cat "$__object/parameter/owner") + +# tarball name changed due to application renaming +if echo "$VERSION" | version_ge 1.7.14; then + src="element-v$VERSION" +else + src="riot-v$VERSION" +fi +archive="$src.tar.gz" +url="https://github.com/vector-im/riot-web/releases/download/v$VERSION/$archive" + +# tar and curl are installed by the __matrix-riot manifest. mktemp is usually +# provided by coreutils and assumed installed. +cat << EOF +set -e + +# Ensure that coreutils is installed. +if [ ! -x \$(which mktemp) ]; then + echo "mktemp is not available on the remote host." >&2 + exit 1 +fi + +# Create temporary working directory. +tmpdir=\$(mktemp -d) +custom_files_dir="\$tmpdir/custom_files" +cd \$tmpdir + +# Download and extract sources. +curl -L '$url' > $archive +tar xf $archive + +# Backup files deployed by __matrix_element. +mkdir -p \$custom_files_dir +for file in $INSTALL_DIR/cdist/*; do + cp "\$file" "\$custom_files_dir" +done + +# Deploy sources and restore configuration. +rm -r '$INSTALL_DIR' +mv '$src' '$INSTALL_DIR' + +for file in \$custom_files_dir/*; do + cp "\$file" '$INSTALL_DIR' +done + +# Chown deployed files to requested owner. +chown -R '$OWNER' '$INSTALL_DIR' + +# Remove temporary working directory. +cd / +rm -r \$tmpdir +EOF diff --git a/type/__matrix_element/man.rst b/type/__matrix_element/man.rst new file mode 100644 index 0000000..0d748a3 --- /dev/null +++ b/type/__matrix_element/man.rst @@ -0,0 +1,103 @@ +cdist-type__matrix_element(7) +============================= + +NAME +---- +cdist-type__matrix_element - Install and configure Element, a web Matrix client. + + +DESCRIPTION +----------- +This type install and configure the Element web client. + + +REQUIRED PARAMETERS +------------------- +install_dir + Root directory of Element's static files. + +version + Release of Element to install. + +OPTIONAL PARAMETERS +------------------- +default_server_name + Name of matrix homeserver to connect to, defaults to 'matrix.org'. + +default_server_url + URL of matrix homeserver to connect to, defaults to 'https://matrix-client.matrix.org'. + +identity_server_url + URL of matrix identity server to connect to, defaults to 'https://vector.im'. + See element documentation + `_` + for details. + +owner + Owner of the deployed files, passed to `chown`. Defaults to 'root'. + +brand + Web UI branding, defaults to 'Element'. + +branding_auth_header_logo_url + A logo image that is shown in the header during authentication flows. + +branding_welcome_background_url + An image to use as a wallpaper outside the app during authentication flows. If an array is passed, an image is chosen randomly for each visit. + +branding_auth_footer_links + a list of links to show in the authentication page footer: `[{"text": "Link + text", "url": "https://link.target"}, {"text": "Other link", ...}]` + +default_country_code + ISO 3166 alpha2 country code to use when showing country selectors, such as + phone number inputs. Defaults to GB. + +privacy_policy_url + Defaults to 'https://element.io/privacy'. + +cookie_policy_url + Defaults to 'https://matrix.org/docs/guides/element_im_cookie_policy'. + +jitsi_domain + Domain name of preferred Jitsi instance (default is jitsi.element.im). This is + used whenever a user clicks on the voice/video call buttons. + +homepage + Path to custom homepage, displayed once logged in. + +welcomepage + Path to custom welcome (= login) page. + +custom_asset + Serve a file a the top-level directory (e.g. /my-custom-logo.svg). Can be specified multiple times. + +BOOLEAN PARAMETERS +------------------- +disable_custom_urls + Disallow the user to change the default homeserver when signing up or logging in. + +EXAMPLES +-------- + +.. code-block:: sh + + __matrix_element my-element --install_dir /var/www/element-web --version 1.5.6 + + +SEE ALSO +-------- +- `cdist-type__matrix_synapse(7) `_ + + +AUTHORS +------- +Timothée Floure + + +COPYING +------- +Copyright \(C) 2019 Timothée Floure. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__matrix_element/manifest b/type/__matrix_element/manifest new file mode 100755 index 0000000..fe937c5 --- /dev/null +++ b/type/__matrix_element/manifest @@ -0,0 +1,118 @@ +#!/bin/sh -e +# +# 2019 Timothée Floure (timothee.floure@ungleich.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . + +# Ignore "Declare and assign separately to avoid masking return values. [SC2155]" +# => not relevant for the type arguments. +# shellcheck disable=SC2155 + +INSTALL_DIR=$(cat "$__object/parameter/install_dir") + +export DEFAULT_SERVER_NAME=$(cat "$__object/parameter/default_server_name") +export DEFAULT_SERVER_URL=$(cat "$__object/parameter/default_server_url") +export IDENTITY_SERVER_URL=$(cat "$__object/parameter/identity_server_url") +export BRAND=$(cat "$__object/parameter/brand") +export DEFAULT_COUNTRY_CODE=$(cat "$__object/parameter/default_country_code") +export ROOM_DIRECTORY_SERVERS=$(cat "$__object/parameter/room_directory_servers") +export PRIVACY_POLICY_URL=$(cat "$__object/parameter/privacy_policy_url") +export COOKIE_POLICY_URL=$(cat "$__object/parameter/cookie_policy_url") +export BRANDING_WELCOME_BACKGROUND_URL=$(cat "$__object/parameter/branding_welcome_background_url") + +if [ -f "$__object/parameter/jitsi_domain" ]; then + export JITSI_DOMAIN=$(cat "$__object/parameter/jitsi_domain") +fi + +if [ -f "$__object/parameter/branding_auth_header_logo_url" ]; then + export BRANDING_AUTH_HEADER_LOGO_URL=$(cat "$__object/parameter/branding_auth_header_logo_url") +fi + +if [ -f "$__object/parameter/branding_auth_footer_links" ]; then + export BRANDING_AUTH_FOOTER_LINKS=$(cat "$__object/parameter/branding_auth_footer_links") +fi + +if [ -f "$__object/parameter/homepage" ]; then + homepage=$(cat "$__object/parameter/homepage") + if [ -f "$homepage" ]; then + upload_homepage=1 + else + export HOME_PAGE_URL=$homepage + fi +fi + +WELCOME_PAGE_URL="welcome.html" +if [ -f "$__object/parameter/welcomepage" ]; then + welcomepage=$(cat "$__object/parameter/welcomepage") + if [ -f welcomepage ]; then + export UPLOAD_WELCOMEPAGE=1 + else + WELCOME_PAGE_URL=$welcomepage + fi +fi +export WELCOME_PAGE_URL + +if [ -f "$__object/parameter/custom_asset" ]; then + "$__object/parameter/custom_asset" | while IFS= read -r file; do + require="__directory/$INSTALL_DIR/cdist" __file "$INSTALL_DIR/cdist/$(basename "$file")" \ + --source "$file" \ + --mode 0664 \ + --state present + done +fi + +if [ -f "$__object/parameter/disable_custom_urls" ]; then + export DISABLE_CUSTOM_URLS='true' +else + export DISABLE_CUSTOM_URLS='false' +fi + +# Owner of the uploaded files. +owner=$(cat "$__object/parameter/owner") + +# Ensure that curl and tar are installed, as they will be required by the +# gencode-remote script. +__package curl --state present +__package tar --state present + +# Generate and deploy configuration file. +mkdir -p "$__object/files" +"$__type/files/config.json.sh" > "$__object/files/config.json" + +# Install the config.json configuration file. The application's sources are +# downloaded and deployed by gencode-remote. +__directory "$INSTALL_DIR/cdist" \ + --owner "$owner" --mode 0755 --parents \ + --state present + +require="__directory/$INSTALL_DIR/cdist" __file "$INSTALL_DIR/cdist/config.json" \ + --source "$__object/files/config.json" \ + --mode 0664 \ + --state present + +if [ $upload_homepage ]; then + require="__directory/$INSTALL_DIR/cdist" __file "$INSTALL_DIR/cdist/home.html" \ + --source "$homepage" \ + --mode 0664 \ + --state present +fi + +if [ $upload_welcomepage ]; then + require="__directory/$INSTALL_DIR/cdist" __file "$INSTALL_DIR/cdist/welcome.html" \ + --source "$welcomepage" \ + --mode 0664 \ + --state present +fi diff --git a/type/__matrix_element/parameter/boolean b/type/__matrix_element/parameter/boolean new file mode 100644 index 0000000..4d77768 --- /dev/null +++ b/type/__matrix_element/parameter/boolean @@ -0,0 +1 @@ +disable_custom_urls diff --git a/type/__matrix_element/parameter/default/brand b/type/__matrix_element/parameter/default/brand new file mode 100644 index 0000000..907f907 --- /dev/null +++ b/type/__matrix_element/parameter/default/brand @@ -0,0 +1 @@ +Element diff --git a/type/__matrix_element/parameter/default/branding_welcome_background_url b/type/__matrix_element/parameter/default/branding_welcome_background_url new file mode 100644 index 0000000..5f5acef --- /dev/null +++ b/type/__matrix_element/parameter/default/branding_welcome_background_url @@ -0,0 +1 @@ +themes/element/img/backgrounds/lake.jpg diff --git a/type/__matrix_element/parameter/default/cookie_policy_url b/type/__matrix_element/parameter/default/cookie_policy_url new file mode 100644 index 0000000..04e9c2b --- /dev/null +++ b/type/__matrix_element/parameter/default/cookie_policy_url @@ -0,0 +1 @@ +https://matrix.org/docs/guides/riot_im_cookie_policy diff --git a/type/__matrix_element/parameter/default/default_country_code b/type/__matrix_element/parameter/default/default_country_code new file mode 100644 index 0000000..30ac4a3 --- /dev/null +++ b/type/__matrix_element/parameter/default/default_country_code @@ -0,0 +1 @@ +GB diff --git a/type/__matrix_element/parameter/default/default_server_name b/type/__matrix_element/parameter/default/default_server_name new file mode 100644 index 0000000..5528ffd --- /dev/null +++ b/type/__matrix_element/parameter/default/default_server_name @@ -0,0 +1 @@ +matrix.org diff --git a/type/__matrix_element/parameter/default/default_server_url b/type/__matrix_element/parameter/default/default_server_url new file mode 100644 index 0000000..2cb9227 --- /dev/null +++ b/type/__matrix_element/parameter/default/default_server_url @@ -0,0 +1 @@ +https://matrix-client.matrix.org diff --git a/type/__matrix_element/parameter/default/identity_server b/type/__matrix_element/parameter/default/identity_server new file mode 100644 index 0000000..e69de29 diff --git a/type/__matrix_element/parameter/default/owner b/type/__matrix_element/parameter/default/owner new file mode 100644 index 0000000..d8649da --- /dev/null +++ b/type/__matrix_element/parameter/default/owner @@ -0,0 +1 @@ +root diff --git a/type/__matrix_element/parameter/default/privacy_policy_url b/type/__matrix_element/parameter/default/privacy_policy_url new file mode 100644 index 0000000..37fa4bc --- /dev/null +++ b/type/__matrix_element/parameter/default/privacy_policy_url @@ -0,0 +1 @@ +https://element.io/privacy diff --git a/type/__matrix_element/parameter/default/room_directory_servers b/type/__matrix_element/parameter/default/room_directory_servers new file mode 100644 index 0000000..4ea73ad --- /dev/null +++ b/type/__matrix_element/parameter/default/room_directory_servers @@ -0,0 +1 @@ +"matrix.org" diff --git a/type/__matrix_element/parameter/optional b/type/__matrix_element/parameter/optional new file mode 100644 index 0000000..2830f81 --- /dev/null +++ b/type/__matrix_element/parameter/optional @@ -0,0 +1,15 @@ +default_server_url +default_server_name +identity_server_url +brand +default_country_code +privacy_policy_url +cookie_policy_url +room_directory_servers +owner +homepage +welcomepage +jitsi_domain +branding_auth_header_logo_url +branding_auth_footer_links +branding_welcome_background_url diff --git a/type/__matrix_element/parameter/optional_multiple b/type/__matrix_element/parameter/optional_multiple new file mode 100644 index 0000000..4c2ca54 --- /dev/null +++ b/type/__matrix_element/parameter/optional_multiple @@ -0,0 +1 @@ +custom_asset diff --git a/type/__matrix_element/parameter/required b/type/__matrix_element/parameter/required new file mode 100644 index 0000000..a76477e --- /dev/null +++ b/type/__matrix_element/parameter/required @@ -0,0 +1,2 @@ +version +install_dir diff --git a/type/__matrix_synapse/files/homeserver.yaml.sh b/type/__matrix_synapse/files/homeserver.yaml.sh new file mode 100755 index 0000000..64b40ee --- /dev/null +++ b/type/__matrix_synapse/files/homeserver.yaml.sh @@ -0,0 +1,2941 @@ +#!/bin/sh +# Note: template originally generated from synapse's 1.26.0 sample config + +set -e + +generate_bind_addresses () { + if [ -n "$BIND_ADDRESSES" ]; then + echo "bind_addresses:" + for addr in $BIND_ADDRESSES; do + echo " - '$addr'" + done + else + echo "bind_addresses: []" + fi +} + +cat << EOF +############################################################### +# THIS FILE HAS BEEN GENERATED BY CDIST. DO NOT EDIT BY HAND. # +############################################################### + +# Configuration file for Synapse. +# +# This is a YAML file: see [1] for a quick introduction. Note in particular +# that *indentation is important*: all the elements of a list or dictionary +# should have the same indentation. +# +# [1] https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html + +## Server ## + +# The public-facing domain of the server +# +# The server_name name will appear at the end of usernames and room addresses +# created on this server. For example if the server_name was example.com, +# usernames on this server would be in the format @user:example.com +# +# In most cases you should avoid using a matrix specific subdomain such as +# matrix.example.com or synapse.example.com as the server_name for the same +# reasons you wouldn't use user@email.example.com as your email address. +# See https://github.com/matrix-org/synapse/blob/master/docs/delegate.md +# for information on how to host Synapse on a subdomain while preserving +# a clean server_name. +# +# The server_name cannot be changed later so it is important to +# configure this correctly before you start Synapse. It should be all +# lowercase and may contain an explicit port. +# Examples: matrix.org, localhost:8080 +# +server_name: "${SERVER_NAME:?}" + +# When running as a daemon, the file to store the pid in +# +pid_file: "${PIDFILE:?}" + +# The absolute URL to the web client which /_matrix/client will redirect +# to if 'webclient' is configured under the 'listeners' configuration. +# +# This option can be also set to the filesystem path to the web client +# which will be served at /_matrix/client/ if 'webclient' is configured +# under the 'listeners' configuration, however this is a security risk: +# https://github.com/matrix-org/synapse#security-note +# +EOF + +if [ -n "$WEB_CLIENT_URL" ]; then + echo "web_client_location: \"$WEB_CLIENT_URL\"" +fi + +cat << EOF +# The public-facing base URL that clients use to access this Homeserver (not +# including _matrix/...). This is the same URL a user might enter into the +# 'Custom Homeserver URL' field on their client. If you use Synapse with a +# reverse proxy, this should be the URL to reach Synapse via the proxy. +# Otherwise, it should be the URL to reach Synapse's client HTTP listener (see +# 'listeners' below). +# +# If this is left unset, it defaults to 'https:///'. (Note that +# that will not work unless you configure Synapse or a reverse-proxy to listen +# on port 443.) +# +public_baseurl: "${BASE_URL:?}" + +# Set the soft limit on the number of file descriptors synapse can use +# Zero is used to indicate synapse should set the soft limit to the +# hard limit. +# +#soft_file_limit: 0 + +# Set to false to disable presence tracking on this homeserver. +# +use_presence: ${USE_PRESENCE:?} + +# Whether to require authentication to retrieve profile data (avatars, +# display names) of other users through the client API. Defaults to +# 'false'. Note that profile data is also available via the federation +# API, so this setting is of limited value if federation is enabled on +# the server. +# +#require_auth_for_profile_requests: true + +# Uncomment to require a user to share a room with another user in order +# to retrieve their profile information. Only checked on Client-Server +# requests. Profile requests from other servers should be checked by the +# requesting server. Defaults to 'false'. +# +#limit_profile_requests_to_users_who_share_rooms: true + +# If set to 'true', removes the need for authentication to access the server's +# public rooms directory through the client API, meaning that anyone can +# query the room directory. Defaults to 'false'. +# +allow_public_rooms_without_auth: ${ALLOW_PUBLIC_ROOMS_WITHOUT_AUTH} + +# If set to 'true', allows any other homeserver to fetch the server's public +# rooms directory via federation. Defaults to 'false'. +# +allow_public_rooms_over_federation: ${ALLOW_PUBLIC_ROOMS_OVER_FEDERATION:?} + +# The default room version for newly created rooms. +# +# Known room versions are listed here: +# https://matrix.org/docs/spec/#complete-list-of-room-versions +# +# For example, for room version 1, default_room_version should be set +# to "1". +# +#default_room_version: "6" + +# The GC threshold parameters to pass to \`gc.set_threshold\`, if defined +# +#gc_thresholds: [700, 10, 10] + +# Set the limit on the returned events in the timeline in the get +# and sync operations. The default value is 100. -1 means no upper limit. +# +# Uncomment the following to increase the limit to 5000. +# +#filter_timeline_limit: 5000 + +# Whether room invites to users on this server should be blocked +# (except those sent by local server admins). The default is False. +# +#block_non_admin_invites: true + +# Room searching +# +# If disabled, new messages will not be indexed for searching and users +# will receive errors when searching for messages. Defaults to enabled. +# +#enable_search: false + +# Prevent outgoing requests from being sent to the following blacklisted IP address +# CIDR ranges. If this option is not specified then it defaults to private IP +# address ranges (see the example below). +# +# The blacklist applies to the outbound requests for federation, identity servers, +# push servers, and for checking key validity for third-party invite events. +# +# (0.0.0.0 and :: are always blacklisted, whether or not they are explicitly +# listed here, since they correspond to unroutable addresses.) +# +# This option replaces federation_ip_range_blacklist in Synapse v1.25.0. +# +#ip_range_blacklist: +# - '127.0.0.0/8' +# - '10.0.0.0/8' +# - '172.16.0.0/12' +# - '192.168.0.0/16' +# - '100.64.0.0/10' +# - '192.0.0.0/24' +# - '169.254.0.0/16' +# - '198.18.0.0/15' +# - '192.0.2.0/24' +# - '198.51.100.0/24' +# - '203.0.113.0/24' +# - '224.0.0.0/4' +# - '::1/128' +# - 'fe80::/10' +# - 'fc00::/7' + +# List of IP address CIDR ranges that should be allowed for federation, +# identity servers, push servers, and for checking key validity for +# third-party invite events. This is useful for specifying exceptions to +# wide-ranging blacklisted target IP ranges - e.g. for communication with +# a push server only visible in your network. +# +# This whitelist overrides ip_range_blacklist and defaults to an empty +# list. +# +#ip_range_whitelist: +# - '192.168.1.1' + +# List of ports that Synapse should listen on, their purpose and their +# configuration. +# +# Options for each listener include: +# +# port: the TCP port to bind to +# +# bind_addresses: a list of local addresses to listen on. The default is +# 'all local interfaces'. +# +# type: the type of listener. Normally 'http', but other valid options are: +# 'manhole' (see docs/manhole.md), +# 'metrics' (see docs/metrics-howto.md), +# 'replication' (see docs/workers.md). +# +# tls: set to true to enable TLS for this listener. Will use the TLS +# key/cert specified in tls_private_key_path / tls_certificate_path. +# +# x_forwarded: Only valid for an 'http' listener. Set to true to use the +# X-Forwarded-For header as the client IP. Useful when Synapse is +# behind a reverse-proxy. +# +# resources: Only valid for an 'http' listener. A list of resources to host +# on this port. Options for each resource are: +# +# names: a list of names of HTTP resources. See below for a list of +# valid resource names. +# +# compress: set to true to enable HTTP compression for this resource. +# +# additional_resources: Only valid for an 'http' listener. A map of +# additional endpoints which should be loaded via dynamic modules. +# +# Valid resource names are: +# +# client: the client-server API (/_matrix/client), and the synapse admin +# API (/_synapse/admin). Also implies 'media' and 'static'. +# +# consent: user consent forms (/_matrix/consent). See +# docs/consent_tracking.md. +# +# federation: the server-server API (/_matrix/federation). Also implies +# 'media', 'keys', 'openid' +# +# keys: the key discovery API (/_matrix/keys). +# +# media: the media API (/_matrix/media). +# +# metrics: the metrics interface. See docs/metrics-howto.md. +# +# openid: OpenID authentication. +# +# replication: the HTTP replication API (/_synapse/replication). See +# docs/workers.md. +# +# static: static resources under synapse/static (/_matrix/static). (Mostly +# useful for 'fallback authentication'.) +# +# webclient: A web client. Requires web_client_location to be set. +# +listeners: + # TLS-enabled listener: for when matrix traffic is sent directly to synapse. + # + # Disabled by default. To enable it, uncomment the following. (Note that you + # will also need to give Synapse a TLS key and certificate: see the TLS section + # below.) + # + #- port: 8448 + # type: http + # tls: true + # resources: + # - names: [client, federation] + + # Unsecure HTTP listener: for when matrix traffic passes through a reverse proxy + # that unwraps TLS. + # + # If you plan to use a reverse proxy, please see + # https://github.com/matrix-org/synapse/blob/master/docs/reverse_proxy.md. + # + - port: ${MAIN_LISTENER_PORT:?} + tls: false + type: http + x_forwarded: true + $(generate_bind_addresses) + + resources: + - names: ${MAIN_LISTENER_RESOURCES:?} + compress: false +EOF + +if [ -n "$ENABLE_REPLICATION" ]; then + cat << EOF + - port: 9093 + $(generate_bind_addresses) + + type: http + resources: + - names: [replication] +EOF +fi + +cat << EOF + # example additional_resources: + # + #additional_resources: + # "/_matrix/my/custom/endpoint": + # module: my_module.CustomRequestHandler + # config: {} + + # Turn on the twisted ssh manhole service on localhost on the given + # port. + # + #- port: 9000 + # bind_addresses: ['::1', '127.0.0.1'] + # type: manhole + +# Forward extremities can build up in a room due to networking delays between +# homeservers. Once this happens in a large room, calculation of the state of +# that room can become quite expensive. To mitigate this, once the number of +# forward extremities reaches a given threshold, Synapse will send an +# org.matrix.dummy_event event, which will reduce the forward extremities +# in the room. +# +# This setting defines the threshold (i.e. number of forward extremities in the +# room) at which dummy events are sent. The default value is 10. +# +#dummy_events_threshold: 5 + + +## Homeserver blocking ## + +# How to reach the server admin, used in ResourceLimitError +# +#admin_contact: 'mailto:admin@server.com' + +# Global blocking +# +#hs_disabled: false +#hs_disabled_message: 'Human readable reason for why the HS is blocked' + +# Monthly Active User Blocking +# +# Used in cases where the admin or server owner wants to limit to the +# number of monthly active users. +# +# 'limit_usage_by_mau' disables/enables monthly active user blocking. When +# enabled and a limit is reached the server returns a 'ResourceLimitError' +# with error type Codes.RESOURCE_LIMIT_EXCEEDED +# +# 'max_mau_value' is the hard limit of monthly active users above which +# the server will start blocking user actions. +# +# 'mau_trial_days' is a means to add a grace period for active users. It +# means that users must be active for this number of days before they +# can be considered active and guards against the case where lots of users +# sign up in a short space of time never to return after their initial +# session. +# +# 'mau_limit_alerting' is a means of limiting client side alerting +# should the mau limit be reached. This is useful for small instances +# where the admin has 5 mau seats (say) for 5 specific people and no +# interest increasing the mau limit further. Defaults to True, which +# means that alerting is enabled +# +#limit_usage_by_mau: false +#max_mau_value: 50 +#mau_trial_days: 2 +#mau_limit_alerting: false + +# If enabled, the metrics for the number of monthly active users will +# be populated, however no one will be limited. If limit_usage_by_mau +# is true, this is implied to be true. +# +#mau_stats_only: false + +# Sometimes the server admin will want to ensure certain accounts are +# never blocked by mau checking. These accounts are specified here. +# +#mau_limit_reserved_threepids: +# - medium: 'email' +# address: 'reserved_user@example.com' + +# Used by phonehome stats to group together related servers. +#server_context: context + +# Resource-constrained homeserver settings +# +# When this is enabled, the room "complexity" will be checked before a user +# joins a new remote room. If it is above the complexity limit, the server will +# disallow joining, or will instantly leave. +# +# Room complexity is an arbitrary measure based on factors such as the number of +# users in the room. +# +limit_remote_rooms: + # Uncomment to enable room complexity checking. + # + enabled: ${LIMIT_REMOTE_ROOM_COMPLEXITY:?} + + # the limit above which rooms cannot be joined. The default is 1.0. + # + complexity: ${REMOTE_ROOM_COMPLEXITY_THRESHOLD:?} + + # override the error which is returned when the room is too complex. + # + complexity_error: "This room is too complex - local complexity policy prevents you from joing." + + # allow server admins to join complex rooms. Default is false. + # + #admins_can_join: true + +# Whether to require a user to be in the room to add an alias to it. +# Defaults to 'true'. +# +#require_membership_for_aliases: false + +# Whether to allow per-room membership profiles through the send of membership +# events with profile information that differ from the target's global profile. +# Defaults to 'true'. +# +#allow_per_room_profiles: false + +# How long to keep redacted events in unredacted form in the database. After +# this period redacted events get replaced with their redacted form in the DB. +# +# Defaults to \`7d\`. Set to \`null\` to disable. +# +#redaction_retention_period: 28d + +# How long to track users' last seen time and IPs in the database. +# +# Defaults to \`28d\`. Set to \`null\` to disable clearing out of old rows. +# +#user_ips_max_age: 14d + +# Message retention policy at the server level. +# +# Room admins and mods can define a retention period for their rooms using the +# 'm.room.retention' state event, and server admins can cap this period by setting +# the 'allowed_lifetime_min' and 'allowed_lifetime_max' config options. +# +# If this feature is enabled, Synapse will regularly look for and purge events +# which are older than the room's maximum retention period. Synapse will also +# filter events received over federation so that events that should have been +# purged are ignored and not stored again. +# +retention: + # The message retention policies feature is disabled by default. Uncomment the + # following line to enable it. + # + enabled: ${ENABLE_MESSAGE_RETENTION_POLICY:?} + + # Default retention policy. If set, Synapse will apply it to rooms that lack the + # 'm.room.retention' state event. Currently, the value of 'min_lifetime' doesn't + # matter much because Synapse doesn't take it into account yet. + # + default_policy: + min_lifetime: ${MESSAGE_RETENTION_POLICY_MIN_LIFETIME:?} + max_lifetime: ${MESSAGE_RETENTION_POLICY_MAX_LIFETIME:?} + + # Retention policy limits. If set, and the state of a room contains a + # 'm.room.retention' event in its state which contains a 'min_lifetime' or a + # 'max_lifetime' that's out of these bounds, Synapse will cap the room's policy + # to these limits when running purge jobs. + # + #allowed_lifetime_min: 1d + #allowed_lifetime_max: 1y + + # Server admins can define the settings of the background jobs purging the + # events which lifetime has expired under the 'purge_jobs' section. + # + # If no configuration is provided, a single job will be set up to delete expired + # events in every room daily. + # + # Each job's configuration defines which range of message lifetimes the job + # takes care of. For example, if 'shortest_max_lifetime' is '2d' and + # 'longest_max_lifetime' is '3d', the job will handle purging expired events in + # rooms whose state defines a 'max_lifetime' that's both higher than 2 days, and + # lower than or equal to 3 days. Both the minimum and the maximum value of a + # range are optional, e.g. a job with no 'shortest_max_lifetime' and a + # 'longest_max_lifetime' of '3d' will handle every room with a retention policy + # which 'max_lifetime' is lower than or equal to three days. + # + # The rationale for this per-job configuration is that some rooms might have a + # retention policy with a low 'max_lifetime', where history needs to be purged + # of outdated messages on a more frequent basis than for the rest of the rooms + # (e.g. every 12h), but not want that purge to be performed by a job that's + # iterating over every room it knows, which could be heavy on the server. + # + # If any purge job is configured, it is strongly recommended to have at least + # a single job with neither 'shortest_max_lifetime' nor 'longest_max_lifetime' + # set, or one job without 'shortest_max_lifetime' and one job without + # 'longest_max_lifetime' set. Otherwise some rooms might be ignored, even if + # 'allowed_lifetime_min' and 'allowed_lifetime_max' are set, because capping a + # room's policy to these values is done after the policies are retrieved from + # Synapse's database (which is done using the range specified in a purge job's + # configuration). + # + #purge_jobs: + # - longest_max_lifetime: 3d + # interval: 12h + # - shortest_max_lifetime: 3d + # interval: 1d + +# Inhibits the /requestToken endpoints from returning an error that might leak +# information about whether an e-mail address is in use or not on this +# homeserver. +# Note that for some endpoints the error situation is the e-mail already being +# used, and for others the error is entering the e-mail being unused. +# If this option is enabled, instead of returning an error, these endpoints will +# act as if no error happened and return a fake session ID ('sid') to clients. +# +#request_token_inhibit_3pid_errors: true + +# A list of domains that the domain portion of 'next_link' parameters +# must match. +# +# This parameter is optionally provided by clients while requesting +# validation of an email or phone number, and maps to a link that +# users will be automatically redirected to after validation +# succeeds. Clients can make use this parameter to aid the validation +# process. +# +# The whitelist is applied whether the homeserver or an +# identity server is handling validation. +# +# The default value is no whitelist functionality; all domains are +# allowed. Setting this value to an empty list will instead disallow +# all domains. +# +#next_link_domain_whitelist: ["matrix.org"] + + +## TLS ## + +# PEM-encoded X509 certificate for TLS. +# This certificate, as of Synapse 1.0, will need to be a valid and verifiable +# certificate, signed by a recognised Certificate Authority. +# +# See 'ACME support' below to enable auto-provisioning this certificate via +# Let's Encrypt. +# +# If supplying your own, be sure to use a \`.pem\` file that includes the +# full certificate chain including any intermediate certificates (for +# instance, if using certbot, use \`fullchain.pem\` as your certificate, +# not \`cert.pem\`). +EOF + +if [ -n "$TLS_CERTIFICATE_PATH" ] && [ -n "$TLS_PRIVATE_KEY_PATH" ]; then + cat << EOF +tls_certificate_path: "$TLS_CERTIFICATE_PATH}" + +# PEM-encoded private key for TLS +# +tls_private_key_path: "$TLS_PRIVATE_KEY_PATH" +EOF +fi + +cat << EOF +# Whether to verify TLS server certificates for outbound federation requests. +# +# Defaults to \`true\`. To disable certificate verification, uncomment the +# following line. +# +#federation_verify_certificates: false + +# The minimum TLS version that will be used for outbound federation requests. +# +# Defaults to \`1\`. Configurable to \`1\`, \`1.1\`, \`1.2\`, or \`1.3\`. Note +# that setting this value higher than \`1.2\` will prevent federation to most +# of the public Matrix network: only configure it to \`1.3\` if you have an +# entirely private federation setup and you can ensure TLS 1.3 support. +# +#federation_client_minimum_tls_version: 1.2 + +# Skip federation certificate verification on the following whitelist +# of domains. +# +# This setting should only be used in very specific cases, such as +# federation over Tor hidden services and similar. For private networks +# of homeservers, you likely want to use a private CA instead. +# +# Only effective if federation_verify_certicates is \`true\`. +# +#federation_certificate_verification_whitelist: +# - lon.example.com +# - *.domain.com +# - *.onion + +# List of custom certificate authorities for federation traffic. +# +# This setting should only normally be used within a private network of +# homeservers. +# +# Note that this list will replace those that are provided by your +# operating environment. Certificates must be in PEM format. +# +#federation_custom_ca_list: +# - myCA1.pem +# - myCA2.pem +# - myCA3.pem + +# ACME support: This will configure Synapse to request a valid TLS certificate +# for your configured \`server_name\` via Let's Encrypt. +# +# Note that ACME v1 is now deprecated, and Synapse currently doesn't support +# ACME v2. This means that this feature currently won't work with installs set +# up after November 2019. For more info, and alternative solutions, see +# https://github.com/matrix-org/synapse/blob/master/docs/ACME.md#deprecation-of-acme-v1 +# +# Note that provisioning a certificate in this way requires port 80 to be +# routed to Synapse so that it can complete the http-01 ACME challenge. +# By default, if you enable ACME support, Synapse will attempt to listen on +# port 80 for incoming http-01 challenges - however, this will likely fail +# with 'Permission denied' or a similar error. +# +# There are a couple of potential solutions to this: +# +# * If you already have an Apache, Nginx, or similar listening on port 80, +# you can configure Synapse to use an alternate port, and have your web +# server forward the requests. For example, assuming you set 'port: 8009' +# below, on Apache, you would write: +# +# ProxyPass /.well-known/acme-challenge http://localhost:8009/.well-known/acme-challenge +# +# * Alternatively, you can use something like \`authbind\` to give Synapse +# permission to listen on port 80. +# +acme: + # ACME support is disabled by default. Set this to \`true\` and uncomment + # tls_certificate_path and tls_private_key_path above to enable it. + # + enabled: false + + # Endpoint to use to request certificates. If you only want to test, + # use Let's Encrypt's staging url: + # https://acme-staging.api.letsencrypt.org/directory + # + #url: https://acme-v01.api.letsencrypt.org/directory + + # Port number to listen on for the HTTP-01 challenge. Change this if + # you are forwarding connections through Apache/Nginx/etc. + # + port: 80 + + # Local addresses to listen on for incoming connections. + # Again, you may want to change this if you are forwarding connections + # through Apache/Nginx/etc. + # + bind_addresses: ['::', '0.0.0.0'] + + # How many days remaining on a certificate before it is renewed. + # + reprovision_threshold: 30 + + # The domain that the certificate should be for. Normally this + # should be the same as your Matrix domain (i.e., 'server_name'), but, + # by putting a file at 'https:///.well-known/matrix/server', + # you can delegate incoming traffic to another server. If you do that, + # you should give the target of the delegation here. + # + # For example: if your 'server_name' is 'example.com', but + # 'https://example.com/.well-known/matrix/server' delegates to + # 'matrix.example.com', you should put 'matrix.example.com' here. + # + # If not set, defaults to your 'server_name'. + # + domain: matrix.example.com + + # file to use for the account key. This will be generated if it doesn't + # exist. + # + # If unspecified, we will use CONFDIR/client.key. + # + account_key_file: /etc/synapse/acme_account.key + +# List of allowed TLS fingerprints for this server to publish along +# with the signing keys for this server. Other matrix servers that +# make HTTPS requests to this server will check that the TLS +# certificates returned by this server match one of the fingerprints. +# +# Synapse automatically adds the fingerprint of its own certificate +# to the list. So if federation traffic is handled directly by synapse +# then no modification to the list is required. +# +# If synapse is run behind a load balancer that handles the TLS then it +# will be necessary to add the fingerprints of the certificates used by +# the loadbalancers to this list if they are different to the one +# synapse is using. +# +# Homeservers are permitted to cache the list of TLS fingerprints +# returned in the key responses up to the "valid_until_ts" returned in +# key. It may be necessary to publish the fingerprints of a new +# certificate and wait until the "valid_until_ts" of the previous key +# responses have passed before deploying it. +# +# You can calculate a fingerprint from a given TLS listener via: +# openssl s_client -connect \$host:\$port < /dev/null 2> /dev/null | +# openssl x509 -outform DER | openssl sha256 -binary | base64 | tr -d '=' +# or by checking matrix.org/federationtester/api/report?server_name=\$host +# +#tls_fingerprints: [{"sha256": ""}] + + +## Federation ## + +# Restrict federation to the following whitelist of domains. +# N.B. we recommend also firewalling your federation listener to limit +# inbound federation traffic as early as possible, rather than relying +# purely on this application-layer restriction. If not specified, the +# default is to whitelist everything. +# +#federation_domain_whitelist: +# - lon.example.com +# - nyc.example.com +# - syd.example.com +EOF + +if [ -n "$DISABLE_FEDERATION" ]; then + echo "federation_domain_whitelist: []" +fi + +cat << EOF + +# Report prometheus metrics on the age of PDUs being sent to and received from +# the following domains. This can be used to give an idea of "delay" on inbound +# and outbound federation, though be aware that any delay can be due to problems +# at either end or with the intermediate network. +# +# By default, no domains are monitored in this way. +# +#federation_metrics_domains: +# - matrix.org +# - example.com + + +## Caching ## + +# Caching can be configured through the following options. +# +# A cache 'factor' is a multiplier that can be applied to each of +# Synapse's caches in order to increase or decrease the maximum +# number of entries that can be stored. + +# The number of events to cache in memory. Not affected by +# caches.global_factor. +# +event_cache_size: ${EVENT_CACHE_SIZE:?} + +caches: + # Controls the global cache factor, which is the default cache factor + # for all caches if a specific factor for that cache is not otherwise + # set. + # + # This can also be set by the "SYNAPSE_CACHE_FACTOR" environment + # variable. Setting by environment variable takes priority over + # setting through the config file. + # + # Defaults to 0.5, which will half the size of all caches. + # + global_factor: ${GLOBAL_CACHE_FACTOR:?} + + # A dictionary of cache name to cache factor for that individual + # cache. Overrides the global cache factor for a given cache. + # + # These can also be set through environment variables comprised + # of "SYNAPSE_CACHE_FACTOR_" + the name of the cache in capital + # letters and underscores. Setting by environment variable + # takes priority over setting through the config file. + # Ex. SYNAPSE_CACHE_FACTOR_GET_USERS_WHO_SHARE_ROOM_WITH_USER=2.0 + # + # Some caches have '*' and other characters that are not + # alphanumeric or underscores. These caches can be named with or + # without the special characters stripped. For example, to specify + # the cache factor for \`*stateGroupCache*\` via an environment + # variable would be \`SYNAPSE_CACHE_FACTOR_STATEGROUPCACHE=2.0\`. + # + per_cache_factors: + #get_users_who_share_room_with_user: 2.0 + + +## Database ## + +# The 'database' setting defines the database that synapse uses to store all of +# its data. +# +# 'name' gives the database engine to use: either 'sqlite3' (for SQLite) or +# 'psycopg2' (for PostgreSQL). +# +# 'args' gives options which are passed through to the database engine, +# except for options starting 'cp_', which are used to configure the Twisted +# connection pool. For a reference to valid arguments, see: +# * for sqlite: https://docs.python.org/3/library/sqlite3.html#sqlite3.connect +# * for postgres: https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS +# * for the connection pool: https://twistedmatrix.com/documents/current/api/twisted.enterprise.adbapi.ConnectionPool.html#__init__ +# +# +# Example SQLite configuration: +# +#database: +# name: sqlite3 +# args: +# database: /path/to/homeserver.db +# +# +# Example Postgres configuration: +# +#database: +# name: psycopg2 +# args: +# user: synapse_user +# password: secretpassword +# database: synapse +# host: localhost +# cp_min: 5 +# cp_max: 10 +# +# For more information on using Synapse with Postgres, see \`docs/postgres.md\`. +# +EOF + +case "${DATABASE_ENGINE:?}" in + sqlite3) + cat << EOF +database: + # The database engine name + name: "sqlite3" + # Arguments to pass to the engine + args: + # Path to the database + database: "${DATABASE_NAME:?}" +EOF + ;; + psycopg2) + cat << EOF +database: + # The database engine name + name: "psycopg2" + # Arguments to pass to the engine + args: + database: "${DATABASE_NAME:?}" + host: "${DATABASE_HOST:?}" + user: "${DATABASE_USER:?}" + password: "$DATABASE_PASSWORD" + cp_min: ${DATABASE_CP_MIN:?} + cp_min: ${DATABASE_CP_MAX:?} +EOF + ;; + *) + echo "Invalid database engine $DATABASE_ENGINE." >&2 + exit 1 + ;; +esac + +cat << EOF +## Logging ## + +# A yaml python logging config file as described by +# https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema +# +log_config: "${LOG_CONFIG_PATH:?}" + + +## Ratelimiting ## + +# Ratelimiting settings for client actions (registration, login, messaging). +# +# Each ratelimiting configuration is made of two parameters: +# - per_second: number of requests a client can send per second. +# - burst_count: number of requests a client can send before being throttled. +# +# Synapse currently uses the following configurations: +# - one for messages that ratelimits sending based on the account the client +# is using +# - one for registration that ratelimits registration requests based on the +# client's IP address. +# - one for login that ratelimits login requests based on the client's IP +# address. +# - one for login that ratelimits login requests based on the account the +# client is attempting to log into. +# - one for login that ratelimits login requests based on the account the +# client is attempting to log into, based on the amount of failed login +# attempts for this account. +# - one for ratelimiting redactions by room admins. If this is not explicitly +# set then it uses the same ratelimiting as per rc_message. This is useful +# to allow room admins to deal with abuse quickly. +# - two for ratelimiting number of rooms a user can join, "local" for when +# users are joining rooms the server is already in (this is cheap) vs +# "remote" for when users are trying to join rooms not on the server (which +# can be more expensive) +# +# The defaults are as shown below. +# +#rc_message: +# per_second: 0.2 +# burst_count: 10 +rc_message: + per_second: ${RC_MESSAGE_PER_SECOND:?} + burst_count: ${RC_MESSAGE_BURST:?} + +#rc_registration: +# per_second: 0.17 +# burst_count: 3 +# +#rc_login: +# address: +# per_second: 0.17 +# burst_count: 3 +# account: +# per_second: 0.17 +# burst_count: 3 +# failed_attempts: +# per_second: 0.17 +# burst_count: 3 +rc_login: + address: + per_second: ${RC_LOGIN_PER_SECOND:?} + burst_count: ${RC_LOGIN_BURST:?} + account: + per_second: ${RC_LOGIN_PER_SECOND:?} + burst_count: ${RC_LOGIN_BURST:?} + failed_attempts: + per_second: ${RC_LOGIN_PER_SECOND:?} + burst_count: ${RC_LOGIN_BURST:?} +# +#rc_admin_redaction: +# per_second: 1 +# burst_count: 50 +# +#rc_joins: +# local: +# per_second: 0.1 +# burst_count: 3 +# remote: +# per_second: 0.01 +# burst_count: 3 + + +# Ratelimiting settings for incoming federation +# +# The rc_federation configuration is made up of the following settings: +# - window_size: window size in milliseconds +# - sleep_limit: number of federation requests from a single server in +# a window before the server will delay processing the request. +# - sleep_delay: duration in milliseconds to delay processing events +# from remote servers by if they go over the sleep limit. +# - reject_limit: maximum number of concurrent federation requests +# allowed from a single server +# - concurrent: number of federation requests to concurrently process +# from a single server +# +# The defaults are as shown below. +# +#rc_federation: +# window_size: 1000 +# sleep_limit: 10 +# sleep_delay: 500 +# reject_limit: 50 +# concurrent: 3 + +# Target outgoing federation transaction frequency for sending read-receipts, +# per-room. +# +# If we end up trying to send out more read-receipts, they will get buffered up +# into fewer transactions. +# +#federation_rr_transactions_per_room_per_second: 50 + + + +## Media Store ## + +# Enable the media store service in the Synapse master. Uncomment the +# following if you are using a separate media store worker. +# +enable_media_repo: ${ENABLE_MEDIA_REPO:?} + +# Directory where uploaded images and attachments are stored. +# +media_store_path: "${DATA_DIR:?}/media_store" + +# Media storage providers allow media to be stored in different +# locations. +# +#media_storage_providers: +# - module: file_system +# # Whether to store newly uploaded local files +# store_local: false +# # Whether to store newly downloaded remote files +# store_remote: false +# # Whether to wait for successful storage for local uploads +# store_synchronous: false +# config: +# directory: /mnt/some/other/directory + +# The largest allowed upload size in bytes +# +max_upload_size: "${MAX_UPLOAD_SIZE:?}" + +# Maximum number of pixels that will be thumbnailed +# +#max_image_pixels: 32M + +# Whether to generate new thumbnails on the fly to precisely match +# the resolution requested by the client. If true then whenever +# a new resolution is requested by the client the server will +# generate a new thumbnail. If false the server will pick a thumbnail +# from a precalculated list. +# +#dynamic_thumbnails: false + +# List of thumbnails to precalculate when an image is uploaded. +# +#thumbnail_sizes: +# - width: 32 +# height: 32 +# method: crop +# - width: 96 +# height: 96 +# method: crop +# - width: 320 +# height: 240 +# method: scale +# - width: 640 +# height: 480 +# method: scale +# - width: 800 +# height: 600 +# method: scale + +# Is the preview URL API enabled? +# +# 'false' by default: uncomment the following to enable it (and specify a +# url_preview_ip_range_blacklist blacklist). +# +url_preview_enabled: ${ENABLE_URL_PREVIEW:?} + +# List of IP address CIDR ranges that the URL preview spider is denied +# from accessing. There are no defaults: you must explicitly +# specify a list for URL previewing to work. You should specify any +# internal services in your network that you do not want synapse to try +# to connect to, otherwise anyone in any Matrix room could cause your +# synapse to issue arbitrary GET requests to your internal services, +# causing serious security issues. +# +# (0.0.0.0 and :: are always blacklisted, whether or not they are explicitly +# listed here, since they correspond to unroutable addresses.) +# +# This must be specified if url_preview_enabled is set. It is recommended that +# you uncomment the following list as a starting point. +# +#url_preview_ip_range_blacklist: +# - '127.0.0.0/8' +# - '10.0.0.0/8' +# - '172.16.0.0/12' +# - '192.168.0.0/16' +# - '100.64.0.0/10' +# - '192.0.0.0/24' +# - '169.254.0.0/16' +# - '198.18.0.0/15' +# - '192.0.2.0/24' +# - '198.51.100.0/24' +# - '203.0.113.0/24' +# - '224.0.0.0/4' +# - '::1/128' +# - 'fe80::/10' +# - 'fc00::/7' + +# List of IP address CIDR ranges that the URL preview spider is allowed +# to access even if they are specified in url_preview_ip_range_blacklist. +# This is useful for specifying exceptions to wide-ranging blacklisted +# target IP ranges - e.g. for enabling URL previews for a specific private +# website only visible in your network. +# +#url_preview_ip_range_whitelist: +# - '192.168.1.1' + +# Optional list of URL matches that the URL preview spider is +# denied from accessing. You should use url_preview_ip_range_blacklist +# in preference to this, otherwise someone could define a public DNS +# entry that points to a private IP address and circumvent the blacklist. +# This is more useful if you know there is an entire shape of URL that +# you know that will never want synapse to try to spider. +# +# Each list entry is a dictionary of url component attributes as returned +# by urlparse.urlsplit as applied to the absolute form of the URL. See +# https://docs.python.org/2/library/urlparse.html#urlparse.urlsplit +# The values of the dictionary are treated as an filename match pattern +# applied to that component of URLs, unless they start with a ^ in which +# case they are treated as a regular expression match. If all the +# specified component matches for a given list item succeed, the URL is +# blacklisted. +# +#url_preview_url_blacklist: +# # blacklist any URL with a username in its URI +# - username: '*' +# +# # blacklist all *.google.com URLs +# - netloc: 'google.com' +# - netloc: '*.google.com' +# +# # blacklist all plain HTTP URLs +# - scheme: 'http' +# +# # blacklist http(s)://www.acme.com/foo +# - netloc: 'www.acme.com' +# path: '/foo' +# +# # blacklist any URL with a literal IPv4 address +# - netloc: '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' + +# The largest allowed URL preview spidering size in bytes +# +#max_spider_size: 10M + +# A list of values for the Accept-Language HTTP header used when +# downloading webpages during URL preview generation. This allows +# Synapse to specify the preferred languages that URL previews should +# be in when communicating with remote servers. +# +# Each value is a IETF language tag; a 2-3 letter identifier for a +# language, optionally followed by subtags separated by '-', specifying +# a country or region variant. +# +# Multiple values can be provided, and a weight can be added to each by +# using quality value syntax (;q=). '*' translates to any language. +# +# Defaults to "en". +# +# Example: +# +# url_preview_accept_language: +# - en-UK +# - en-US;q=0.9 +# - fr;q=0.8 +# - *;q=0.7 +# +url_preview_accept_language: +# - en + + +## Captcha ## +# See docs/CAPTCHA_SETUP.md for full details of configuring this. + +# This homeserver's ReCAPTCHA public key. Must be specified if +# enable_registration_captcha is enabled. +# +#recaptcha_public_key: "YOUR_PUBLIC_KEY" + +# This homeserver's ReCAPTCHA private key. Must be specified if +# enable_registration_captcha is enabled. +# +#recaptcha_private_key: "YOUR_PRIVATE_KEY" + +# Uncomment to enable ReCaptcha checks when registering, preventing signup +# unless a captcha is answered. Requires a valid ReCaptcha +# public/private key. Defaults to 'false'. +# +#enable_registration_captcha: true + +# The API endpoint to use for verifying m.login.recaptcha responses. +# Defaults to "https://www.recaptcha.net/recaptcha/api/siteverify". +# +#recaptcha_siteverify_api: "https://my.recaptcha.site" + + +## TURN ## + +# The public URIs of the TURN server to give to clients + +EOF + +if [ -n "$TURN_URIS" ]; then + echo "turn_uris:" + for uri in $TURN_URIS; do + echo " - '$uri'" + done +else + echo "# turn_uris: []" +fi + +cat << EOF +# The shared secret used to compute passwords for the TURN server +# +EOF + +if [ -n "$TURN_SHARED_SECRET" ]; then + echo "turn_shared_secret: \"$TURN_SHARED_SECRET\"" +fi + +cat << EOF +# The Username and password if the TURN server needs them and +# does not use a token +# +EOF + +if [ -n "$TURN_USERNAME" ] || [ "$TURN_PASSWORD" ]; then + cat <<- EOF + turn_username: "$TURN_USERNAME" + turn_password: "$TURN_PASSWORD" + EOF +fi + +cat << EOF +# How long generated TURN credentials last +# +turn_user_lifetime: ${TURN_USER_LIFETIME:?} + +# Whether guests should be allowed to use the TURN server. +# This defaults to True, otherwise VoIP will be unreliable for guests. +# However, it does introduce a slight security risk as it allows users to +# connect to arbitrary endpoints without having first signed up for a +# valid account (e.g. by passing a CAPTCHA). +# +#turn_allow_guests: true + + +## Registration ## +# +# Registration can be rate-limited using the parameters in the "Ratelimiting" +# section of this file. + +# Enable registration for new users. +# +enable_registration: ${ENABLE_REGISTRATIONS:?} + +# Optional account validity configuration. This allows for accounts to be denied +# any request after a given period. +# +# Once this feature is enabled, Synapse will look for registered users without an +# expiration date at startup and will add one to every account it found using the +# current settings at that time. +# This means that, if a validity period is set, and Synapse is restarted (it will +# then derive an expiration date from the current validity period), and some time +# after that the validity period changes and Synapse is restarted, the users' +# expiration dates won't be updated unless their account is manually renewed. This +# date will be randomly selected within a range [now + period - d ; now + period], +# where d is equal to 10% of the validity period. +# +account_validity: + # The account validity feature is disabled by default. Uncomment the + # following line to enable it. + # + #enabled: true + + # The period after which an account is valid after its registration. When + # renewing the account, its validity period will be extended by this amount + # of time. This parameter is required when using the account validity + # feature. + # + #period: 6w + + # The amount of time before an account's expiry date at which Synapse will + # send an email to the account's email address with a renewal link. By + # default, no such emails are sent. + # + # If you enable this setting, you will also need to fill out the 'email' + # configuration section. You should also check that 'public_baseurl' is set + # correctly. + # + #renew_at: 1w + + # The subject of the email sent out with the renewal link. '%(app)s' can be + # used as a placeholder for the 'app_name' parameter from the 'email' + # section. + # + # Note that the placeholder must be written '%(app)s', including the + # trailing 's'. + # + # If this is not set, a default value is used. + # + #renew_email_subject: "Renew your %(app)s account" + + # Directory in which Synapse will try to find templates for the HTML files to + # serve to the user when trying to renew an account. If not set, default + # templates from within the Synapse package will be used. + # + #template_dir: "res/templates" + + # File within 'template_dir' giving the HTML to be displayed to the user after + # they successfully renewed their account. If not set, default text is used. + # + #account_renewed_html_path: "account_renewed.html" + + # File within 'template_dir' giving the HTML to be displayed when the user + # tries to renew an account with an invalid renewal token. If not set, + # default text is used. + # + #invalid_token_html_path: "invalid_token.html" + +# Time that a user's session remains valid for, after they log in. +# +# Note that this is not currently compatible with guest logins. +# +# Note also that this is calculated at login time: changes are not applied +# retrospectively to users who have already logged in. +# +# By default, this is infinite. +# +#session_lifetime: 24h + +# The user must provide all of the below types of 3PID when registering. +# +#registrations_require_3pid: +# - email +# - msisdn +EOF + +if [ -n "$REGISTRATION_REQUIRES_EMAIL" ]; then + echo "registrations_require_3pid: [email]" +fi + +cat << EOF +# Explicitly disable asking for MSISDNs from the registration +# flow (overrides registrations_require_3pid if MSISDNs are set as required) +# +#disable_msisdn_registration: true + +# Mandate that users are only allowed to associate certain formats of +# 3PIDs with accounts on this server. +# +#allowed_local_3pids: +# - medium: email +# pattern: '.*@matrix\.org' +# - medium: email +# pattern: '.*@vector\.im' +# - medium: msisdn +# pattern: '\+44' +EOF + +if [ -n "$RESGISTRATION_ALLOWS_EMAIL_PATTERN" ]; then + echo "allowed_local_3pids:" + for pattern in $RESGISTRATION_ALLOWS_EMAIL_PATTERN; do + cat << EOF + - medium: email + pattern: $pattern +EOF + done +fi + +cat << EOF +# Enable 3PIDs lookup requests to identity servers from this server. +# +enable_3pid_lookup: ${ENABLE_3PID_LOOKUPS:?} + +# If set, allows registration of standard or admin accounts by anyone who +# has the shared secret, even if registration is otherwise disabled. +EOF + +if [ -n "$REGISTRATION_SHARED_SECRET" ]; then + echo "registration_shared_secret: '$REGISTRATION_SHARED_SECRET'" +else + echo "# registration_shared_secret: 'secret'" +fi + +cat << EOF + +# Set the number of bcrypt rounds used to generate password hash. +# Larger numbers increase the work factor needed to generate the hash. +# The default number is 12 (which equates to 2^12 rounds). +# N.B. that increasing this will exponentially increase the time required +# to register or login - e.g. 24 => 2^24 rounds which will take >20 mins. +# +#bcrypt_rounds: 12 + +# Allows users to register as guests without a password/email/etc, and +# participate in rooms hosted on this server which have been made +# accessible to anonymous users. + +allow_guest_access: ${ALLOW_GUEST_ACCESS:?} + +# The identity server which we suggest that clients should use when users log +# in on this server. +# +# (By default, no suggestion is made, so it is left up to the client.) +# +#default_identity_server: https://matrix.org +EOF + +if [ -n "$DEFAULT_IDENTITY_SERVER" ]; then + echo "default_identity_server: \"$DEFAULT_IDENTITY_SERVER\"" +fi + +cat << EOF +# Handle threepid (email/phone etc) registration and password resets through a set of +# *trusted* identity servers. Note that this allows the configured identity server to +# reset passwords for accounts! +# +# Be aware that if \`email\` is not set, and SMTP options have not been +# configured in the email config block, registration and user password resets via +# email will be globally disabled. +# +# Additionally, if \`msisdn\` is not set, registration and password resets via msisdn +# will be disabled regardless, and users will not be able to associate an msisdn +# identifier to their account. This is due to Synapse currently not supporting +# any method of sending SMS messages on its own. +# +# To enable using an identity server for operations regarding a particular third-party +# identifier type, set the value to the URL of that identity server as shown in the +# examples below. +# +# Servers handling the these requests must answer the \`/requestToken\` endpoints defined +# by the Matrix Identity Service API specification: +# https://matrix.org/docs/spec/identity_service/latest +# +account_threepid_delegates: + #email: https://example.com # Delegate email sending to example.com + #msisdn: http://localhost:8090 # Delegate SMS sending to this local process + +# Whether users are allowed to change their displayname after it has +# been initially set. Useful when provisioning users based on the +# contents of a third-party directory. +# +# Does not apply to server administrators. Defaults to 'true' +# +enable_set_displayname: ${ENABLE_SET_DISPLAYNAME:?} + +# Whether users are allowed to change their avatar after it has been +# initially set. Useful when provisioning users based on the contents +# of a third-party directory. +# +# Does not apply to server administrators. Defaults to 'true' +# +#enable_set_avatar_url: false + +# Whether users can change the 3PIDs associated with their accounts +# (email address and msisdn). +# +# Defaults to 'true' +# +enable_3pid_changes: ${ENABLE_3PID_CHANGES:?} + +# Users who register on this homeserver will automatically be joined +# to these rooms. +# +# By default, any room aliases included in this list will be created +# as a publicly joinable room when the first user registers for the +# homeserver. This behaviour can be customised with the settings below. +# +#auto_join_rooms: +# - "#example:example.com" +EOF + +if [ -n "$AUTO_JOIN_ROOMS" ]; then + echo "auto_join_rooms:" + for room in $AUTO_JOIN_ROOMS; do + cat << EOF + - "$room" +EOF + done +fi + +cat << EOF +# Where auto_join_rooms are specified, setting this flag ensures that the +# the rooms exist by creating them when the first user on the +# homeserver registers. +# +# By default the auto-created rooms are publicly joinable from any federated +# server. Use the autocreate_auto_join_rooms_federated and +# autocreate_auto_join_room_preset settings below to customise this behaviour. +# +# Setting to false means that if the rooms are not manually created, +# users cannot be auto-joined since they do not exist. +# +# Defaults to true. Uncomment the following line to disable automatically +# creating auto-join rooms. +# +#autocreate_auto_join_rooms: false + +# Whether the auto_join_rooms that are auto-created are available via +# federation. Only has an effect if autocreate_auto_join_rooms is true. +# +# Note that whether a room is federated cannot be modified after +# creation. +# +# Defaults to true: the room will be joinable from other servers. +# Uncomment the following to prevent users from other homeservers from +# joining these rooms. +# +#autocreate_auto_join_rooms_federated: false + +# The room preset to use when auto-creating one of auto_join_rooms. Only has an +# effect if autocreate_auto_join_rooms is true. +# +# This can be one of "public_chat", "private_chat", or "trusted_private_chat". +# If a value of "private_chat" or "trusted_private_chat" is used then +# auto_join_mxid_localpart must also be configured. +# +# Defaults to "public_chat", meaning that the room is joinable by anyone, including +# federated servers if autocreate_auto_join_rooms_federated is true (the default). +# Uncomment the following to require an invitation to join these rooms. +# +#autocreate_auto_join_room_preset: private_chat + +# The local part of the user id which is used to create auto_join_rooms if +# autocreate_auto_join_rooms is true. If this is not provided then the +# initial user account that registers will be used to create the rooms. +# +# The user id is also used to invite new users to any auto-join rooms which +# are set to invite-only. +# +# It *must* be configured if autocreate_auto_join_room_preset is set to +# "private_chat" or "trusted_private_chat". +# +# Note that this must be specified in order for new users to be correctly +# invited to any auto-join rooms which have been set to invite-only (either +# at the time of creation or subsequently). +# +# Note that, if the room already exists, this user must be joined and +# have the appropriate permissions to invite new members. +# +#auto_join_mxid_localpart: system + +# When auto_join_rooms is specified, setting this flag to false prevents +# guest accounts from being automatically joined to the rooms. +# +# Defaults to true. +# +#auto_join_rooms_for_guests: false + + +## Metrics ### + +# Enable collection and rendering of performance metrics +# +enable_metrics: ${EXPOSE_METRICS:?} + +# Enable sentry integration +# NOTE: While attempts are made to ensure that the logs don't contain +# any sensitive information, this cannot be guaranteed. By enabling +# this option the sentry server may therefore receive sensitive +# information, and it in turn may then diseminate sensitive information +# through insecure notification channels if so configured. +# +#sentry: +# dsn: "..." + +# Flags to enable Prometheus metrics which are not suitable to be +# enabled by default, either for performance reasons or limited use. +# +metrics_flags: + # Publish synapse_federation_known_servers, a gauge of the number of + # servers this homeserver knows about, including itself. May cause + # performance problems on large homeservers. + # + #known_servers: true + +# Whether or not to report anonymized homeserver usage statistics. +# +report_stats: ${REPORT_STATS:?} + +# The endpoint to report the anonymized homeserver usage statistics to. +# Defaults to https://matrix.org/report-usage-stats/push +# +#report_stats_endpoint: https://example.com/report-usage-stats/push + + +## API Configuration ## + +# A list of event types that will be included in the room_invite_state +# +#room_invite_state_types: +# - "m.room.join_rules" +# - "m.room.canonical_alias" +# - "m.room.avatar" +# - "m.room.encryption" +# - "m.room.name" + + +# A list of application service config files to use +# +#app_service_config_files: +# - app_service_1.yaml +# - app_service_2.yaml +EOF + +if [ -n "$APP_SERVICE_CONFIG_FILES" ]; then + echo "app_service_config_files:" + for file in $APP_SERVICE_CONFIG_FILES; do + echo " - $file" + done +fi + +cat << EOF +# Uncomment to enable tracking of application service IP addresses. Implicitly +# enables MAU tracking for application service users. +# +#track_appservice_user_ips: true + + +# a secret which is used to sign access tokens. If none is specified, +# the registration_shared_secret is used, if one is given; otherwise, +# a secret key is derived from the signing key. +# +# macaroon_secret_key: "JCMj1A@Me_tSnQwS@,LeInKrEPr@..w4Q6reqqeYWLC:k4tFLn" + +# a secret which is used to calculate HMACs for form values, to stop +# falsification of values. Must be specified for the User Consent +# forms to work. +# +# form_secret: "Hfc:voJY1;,L==VSuq^^@D8Dpa8,Lm13YVnLwLA&2wmfnPloy8" + +## Signing Keys ## + +# Path to the signing key to sign messages with +# +signing_key_path: "${SIGNING_KEY_PATH:?}" + +# The keys that the server used to sign messages with but won't use +# to sign new messages. +# +old_signing_keys: + # For each key, \`key\` should be the base64-encoded public key, and + # \`expired_ts\` should be the time (in milliseconds since the unix epoch) that + # it was last used. + # + # It is possible to build an entry from an old signing.key file using the + # \`export_signing_key\` script which is provided with synapse. + # + # For example: + # + #"ed25519:id": { key: "base64string", expired_ts: 123456789123 } + +# How long key response published by this server is valid for. +# Used to set the valid_until_ts in /key/v2 APIs. +# Determines how quickly servers will query to check which keys +# are still valid. +# +#key_refresh_interval: 1d + +# The trusted servers to download signing keys from. +# +# When we need to fetch a signing key, each server is tried in parallel. +# +# Normally, the connection to the key server is validated via TLS certificates. +# Additional security can be provided by configuring a \`verify key\`, which +# will make synapse check that the response is signed by that key. +# +# This setting supercedes an older setting named \`perspectives\`. The old format +# is still supported for backwards-compatibility, but it is deprecated. +# +# 'trusted_key_servers' defaults to matrix.org, but using it will generate a +# warning on start-up. To suppress this warning, set +# 'suppress_key_server_warning' to true. +# +# Options for each entry in the list include: +# +# server_name: the name of the server. required. +# +# verify_keys: an optional map from key id to base64-encoded public key. +# If specified, we will check that the response is signed by at least +# one of the given keys. +# +# accept_keys_insecurely: a boolean. Normally, if \`verify_keys\` is unset, +# and federation_verify_certificates is not \`true\`, synapse will refuse +# to start, because this would allow anyone who can spoof DNS responses +# to masquerade as the trusted key server. If you know what you are doing +# and are sure that your network environment provides a secure connection +# to the key server, you can set this to \`true\` to override this +# behaviour. +# +# An example configuration might look like: +# +#trusted_key_servers: +# - server_name: "my_trusted_server.example.com" +# verify_keys: +# "ed25519:auto": "abcdefghijklmnopqrstuvwxyzabcdefghijklmopqr" +# - server_name: "my_other_trusted_server.example.com" +# +trusted_key_servers: + - server_name: "matrix.org" + +# Uncomment the following to disable the warning that is emitted when the +# trusted_key_servers include 'matrix.org'. See above. +# +#suppress_key_server_warning: true + +# The signing keys to use when acting as a trusted key server. If not specified +# defaults to the server signing key. +# +# Can contain multiple keys, one per line. +# +#key_server_signing_keys_path: "key_server_signing_keys.key" + + +## Single sign-on integration ## + +# The following settings can be used to make Synapse use a single sign-on +# provider for authentication, instead of its internal password database. +# +# You will probably also want to set the following options to \`false\` to +# disable the regular login/registration flows: +# * enable_registration +# * password_config.enabled +# +# You will also want to investigate the settings under the "sso" configuration +# section below. + +# Enable SAML2 for registration and login. Uses pysaml2. +# +# At least one of \`sp_config\` or \`config_path\` must be set in this section to +# enable SAML login. +# +# Once SAML support is enabled, a metadata file will be exposed at +# https://:/_matrix/saml2/metadata.xml, which you may be able to +# use to configure your SAML IdP with. Alternatively, you can manually configure +# the IdP to use an ACS location of +# https://:/_matrix/saml2/authn_response. +# +saml2_config: + # \`sp_config\` is the configuration for the pysaml2 Service Provider. + # See pysaml2 docs for format of config. + # + # Default values will be used for the 'entityid' and 'service' settings, + # so it is not normally necessary to specify them unless you need to + # override them. + # + sp_config: + # Point this to the IdP's metadata. You must provide either a local + # file via the \`local\` attribute or (preferably) a URL via the + # \`remote\` attribute. + # + #metadata: + # local: ["saml2/idp.xml"] + # remote: + # - url: https://our_idp/metadata.xml +EOF + +if [ -n "$SAML2_IDP_METADATA_URL" ]; then + cat << EOF + metadata: + remote: + - url: "$SAML2_IDP_METADATA_URL" +EOF +fi + +if [ -n "$SAML2_SP_CERT" ] || [ -n "$SAML2_SP_KEY" ]; then + cat << EOF + key_file: "$SAML2_SP_KEY" + cert_file: "$SAML2_SP_CERT" +EOF +fi + +cat << EOF + # Allowed clock difference in seconds between the homeserver and IdP. + # + # Uncomment the below to increase the accepted time difference from 0 to 3 seconds. + # + #accepted_time_diff: 3 + + # By default, the user has to go to our login page first. If you'd like + # to allow IdP-initiated login, set 'allow_unsolicited: true' in a + # 'service.sp' section: + # + #service: + # sp: + # allow_unsolicited: true + + # The examples below are just used to generate our metadata xml, and you + # may well not need them, depending on your setup. Alternatively you + # may need a whole lot more detail - see the pysaml2 docs! + + #description: ["My awesome SP", "en"] + #name: ["Test SP", "en"] + + #ui_info: + # display_name: + # - lang: en + # text: "Display Name is the descriptive name of your service." + # description: + # - lang: en + # text: "Description should be a short paragraph explaining the purpose of the service." + # information_url: + # - lang: en + # text: "https://example.com/terms-of-service" + # privacy_statement_url: + # - lang: en + # text: "https://example.com/privacy-policy" + # keywords: + # - lang: en + # text: ["Matrix", "Element"] + # logo: + # - lang: en + # text: "https://example.com/logo.svg" + # width: "200" + # height: "80" + + #organization: + # name: Example com + # display_name: + # - ["Example co", "en"] + # url: "http://example.com" + + #contact_person: + # - given_name: Bob + # sur_name: "the Sysadmin" + # email_address": ["admin@example.com"] + # contact_type": technical + + # Instead of putting the config inline as above, you can specify a + # separate pysaml2 configuration file: + # + #config_path: "/etc/synapse/sp_conf.py" + + # The lifetime of a SAML session. This defines how long a user has to + # complete the authentication process, if allow_unsolicited is unset. + # The default is 15 minutes. + # + #saml_session_lifetime: 5m + + # An external module can be provided here as a custom solution to + # mapping attributes returned from a saml provider onto a matrix user. + # + user_mapping_provider: + # The custom module's class. Uncomment to use a custom module. + # + #module: mapping_provider.SamlMappingProvider +EOF + +if [ -n "$SAML2_MAPPING_PROVIDER_MODULE" ]; then + cat << EOF + module: "$SAML2_MAPPING_PROVIDER_MODULE" +EOF +fi + +cat << EOF + # Custom configuration values for the module. Below options are + # intended for the built-in provider, they should be changed if + # using a custom module. This section will be passed as a Python + # dictionary to the module's \`parse_config\` method. + # + config: + # The SAML attribute (after mapping via the attribute maps) to use + # to derive the Matrix ID from. 'uid' by default. + # + # Note: This used to be configured by the + # saml2_config.mxid_source_attribute option. If that is still + # defined, its value will be used instead. + # + #mxid_source_attribute: displayName + + # The mapping system to use for mapping the saml attribute onto a + # matrix ID. + # + # Options include: + # * 'hexencode' (which maps unpermitted characters to '=xx') + # * 'dotreplace' (which replaces unpermitted characters with + # '.'). + # The default is 'hexencode'. + # + # Note: This used to be configured by the + # saml2_config.mxid_mapping option. If that is still defined, its + # value will be used instead. + # + #mxid_mapping: dotreplace +EOF + +if [ -n "$SAML2_MAPPING_PROVIDER_EXTRA_CONFIG" ]; then + echo "$SAML2_MAPPING_PROVIDER_EXTRA_CONFIG" | while IFS= read -r entry; do + cat << EOF + $entry +EOF + done +fi + +cat << EOF + + # In previous versions of synapse, the mapping from SAML attribute to + # MXID was always calculated dynamically rather than stored in a + # table. For backwards- compatibility, we will look for user_ids + # matching such a pattern before creating a new account. + # + # This setting controls the SAML attribute which will be used for this + # backwards-compatibility lookup. Typically it should be 'uid', but if + # the attribute maps are changed, it may be necessary to change it. + # + # The default is 'uid'. + # + #grandfathered_mxid_source_attribute: upn + + # It is possible to configure Synapse to only allow logins if SAML attributes + # match particular values. The requirements can be listed under + # \`attribute_requirements\` as shown below. All of the listed attributes must + # match for the login to be permitted. + # + #attribute_requirements: + # - attribute: userGroup + # value: "staff" + # - attribute: department + # value: "sales" + + # If the metadata XML contains multiple IdP entities then the \`idp_entityid\` + # option must be set to the entity to redirect users to. + # + # Most deployments only have a single IdP entity and so should omit this + # option. + # + #idp_entityid: 'https://our_idp/entityid' + + +# List of OpenID Connect (OIDC) / OAuth 2.0 identity providers, for registration +# and login. +# +# Options for each entry include: +# +# idp_id: a unique identifier for this identity provider. Used internally +# by Synapse; should be a single word such as 'github'. +# +# Note that, if this is changed, users authenticating via that provider +# will no longer be recognised as the same user! +# +# idp_name: A user-facing name for this identity provider, which is used to +# offer the user a choice of login mechanisms. +# +# idp_icon: An optional icon for this identity provider, which is presented +# by identity picker pages. If given, must be an MXC URI of the format +# mxc:///. (An easy way to obtain such an MXC URI +# is to upload an image to an (unencrypted) room and then copy the "url" +# from the source of the event.) +# +# discover: set to 'false' to disable the use of the OIDC discovery mechanism +# to discover endpoints. Defaults to true. +# +# issuer: Required. The OIDC issuer. Used to validate tokens and (if discovery +# is enabled) to discover the provider's endpoints. +# +# client_id: Required. oauth2 client id to use. +# +# client_secret: Required. oauth2 client secret to use. +# +# client_auth_method: auth method to use when exchanging the token. Valid +# values are 'client_secret_basic' (default), 'client_secret_post' and +# 'none'. +# +# scopes: list of scopes to request. This should normally include the "openid" +# scope. Defaults to ["openid"]. +# +# authorization_endpoint: the oauth2 authorization endpoint. Required if +# provider discovery is disabled. +# +# token_endpoint: the oauth2 token endpoint. Required if provider discovery is +# disabled. +# +# userinfo_endpoint: the OIDC userinfo endpoint. Required if discovery is +# disabled and the 'openid' scope is not requested. +# +# jwks_uri: URI where to fetch the JWKS. Required if discovery is disabled and +# the 'openid' scope is used. +# +# skip_verification: set to 'true' to skip metadata verification. Use this if +# you are connecting to a provider that is not OpenID Connect compliant. +# Defaults to false. Avoid this in production. +# +# user_profile_method: Whether to fetch the user profile from the userinfo +# endpoint. Valid values are: 'auto' or 'userinfo_endpoint'. +# +# Defaults to 'auto', which fetches the userinfo endpoint if 'openid' is +# included in 'scopes'. Set to 'userinfo_endpoint' to always fetch the +# userinfo endpoint. +# +# allow_existing_users: set to 'true' to allow a user logging in via OIDC to +# match a pre-existing account instead of failing. This could be used if +# switching from password logins to OIDC. Defaults to false. +# +# user_mapping_provider: Configuration for how attributes returned from a OIDC +# provider are mapped onto a matrix user. This setting has the following +# sub-properties: +# +# module: The class name of a custom mapping module. Default is +# 'synapse.handlers.oidc_handler.JinjaOidcMappingProvider'. +# See https://github.com/matrix-org/synapse/blob/master/docs/sso_mapping_providers.md#openid-mapping-providers +# for information on implementing a custom mapping provider. +# +# config: Configuration for the mapping provider module. This section will +# be passed as a Python dictionary to the user mapping provider +# module's \`parse_config\` method. +# +# For the default provider, the following settings are available: +# +# sub: name of the claim containing a unique identifier for the +# user. Defaults to 'sub', which OpenID Connect compliant +# providers should provide. +# +# localpart_template: Jinja2 template for the localpart of the MXID. +# If this is not set, the user will be prompted to choose their +# own username. +# +# display_name_template: Jinja2 template for the display name to set +# on first login. If unset, no displayname will be set. +# +# extra_attributes: a map of Jinja2 templates for extra attributes +# to send back to the client during login. +# Note that these are non-standard and clients will ignore them +# without modifications. +# +# When rendering, the Jinja2 templates are given a 'user' variable, +# which is set to the claims returned by the UserInfo Endpoint and/or +# in the ID Token. +# +# See https://github.com/matrix-org/synapse/blob/master/docs/openid.md +# for information on how to configure these options. +# +# For backwards compatibility, it is also possible to configure a single OIDC +# provider via an 'oidc_config' setting. This is now deprecated and admins are +# advised to migrate to the 'oidc_providers' format. (When doing that migration, +# use 'oidc' for the idp_id to ensure that existing users continue to be +# recognised.) +# +oidc_providers: + # Generic example + # + #- idp_id: my_idp + # idp_name: "My OpenID provider" + # idp_icon: "mxc://example.com/mediaid" + # discover: false + # issuer: "https://accounts.example.com/" + # client_id: "provided-by-your-issuer" + # client_secret: "provided-by-your-issuer" + # client_auth_method: client_secret_post + # scopes: ["openid", "profile"] + # authorization_endpoint: "https://accounts.example.com/oauth2/auth" + # token_endpoint: "https://accounts.example.com/oauth2/token" + # userinfo_endpoint: "https://accounts.example.com/userinfo" + # jwks_uri: "https://accounts.example.com/.well-known/jwks.json" + # skip_verification: true + + # For use with Keycloak + # + #- idp_id: keycloak + # idp_name: Keycloak + # issuer: "https://127.0.0.1:8443/auth/realms/my_realm_name" + # client_id: "synapse" + # client_secret: "copy secret generated in Keycloak UI" + # scopes: ["openid", "profile"] + + # For use with Github + # + #- idp_id: github + # idp_name: Github + # discover: false + # issuer: "https://github.com/" + # client_id: "your-client-id" # TO BE FILLED + # client_secret: "your-client-secret" # TO BE FILLED + # authorization_endpoint: "https://github.com/login/oauth/authorize" + # token_endpoint: "https://github.com/login/oauth/access_token" + # userinfo_endpoint: "https://api.github.com/user" + # scopes: ["read:user"] + # user_mapping_provider: + # config: + # subject_claim: "id" + # localpart_template: "{ user.login }" + # display_name_template: "{ user.name }" + + +# Enable Central Authentication Service (CAS) for registration and login. +# +cas_config: + # Uncomment the following to enable authorization against a CAS server. + # Defaults to false. + # + #enabled: true + + # The URL of the CAS authorization endpoint. + # + #server_url: "https://cas-server.com" + + # The public URL of the homeserver. + # + #service_url: "https://homeserver.domain.com:8448" + + # The attribute of the CAS response to use as the display name. + # + # If unset, no displayname will be set. + # + #displayname_attribute: name + + # It is possible to configure Synapse to only allow logins if CAS attributes + # match particular values. All of the keys in the mapping below must exist + # and the values must match the given value. Alternately if the given value + # is None then any value is allowed (the attribute just must exist). + # All of the listed attributes must match for the login to be permitted. + # + #required_attributes: + # userGroup: "staff" + # department: None + + +# Additional settings to use with single-sign on systems such as OpenID Connect, +# SAML2 and CAS. +# +sso: + # A list of client URLs which are whitelisted so that the user does not + # have to confirm giving access to their account to the URL. Any client + # whose URL starts with an entry in the following list will not be subject + # to an additional confirmation step after the SSO login is completed. + # + # WARNING: An entry such as "https://my.client" is insecure, because it + # will also match "https://my.client.evil.site", exposing your users to + # phishing attacks from evil.site. To avoid this, include a slash after the + # hostname: "https://my.client/". + # + # The login fallback page (used by clients that don't natively support the + # required login flows) is automatically whitelisted in addition to any URLs + # in this list. + # + # By default, this list is empty. + # + #client_whitelist: + # - https://riot.im/develop + # - https://my.custom.client/ + + # Directory in which Synapse will try to find the template files below. + # If not set, or the files named below are not found within the template + # directory, default templates from within the Synapse package will be used. + # + # Synapse will look for the following templates in this directory: + # + # * HTML page to prompt the user to choose an Identity Provider during + # login: 'sso_login_idp_picker.html'. + # + # This is only used if multiple SSO Identity Providers are configured. + # + # When rendering, this template is given the following variables: + # * redirect_url: the URL that the user will be redirected to after + # login. Needs manual escaping (see + # https://jinja.palletsprojects.com/en/2.11.x/templates/#html-escaping). + # + # * server_name: the homeserver's name. + # + # * providers: a list of available Identity Providers. Each element is + # an object with the following attributes: + # * idp_id: unique identifier for the IdP + # * idp_name: user-facing name for the IdP + # + # The rendered HTML page should contain a form which submits its results + # back as a GET request, with the following query parameters: + # + # * redirectUrl: the client redirect URI (ie, the \`redirect_url\` passed + # to the template) + # + # * idp: the 'idp_id' of the chosen IDP. + # + # * HTML page for a confirmation step before redirecting back to the client + # with the login token: 'sso_redirect_confirm.html'. + # + # When rendering, this template is given three variables: + # * redirect_url: the URL the user is about to be redirected to. Needs + # manual escaping (see + # https://jinja.palletsprojects.com/en/2.11.x/templates/#html-escaping). + # + # * display_url: the same as \`redirect_url\`, but with the query + # parameters stripped. The intention is to have a + # human-readable URL to show to users, not to use it as + # the final address to redirect to. Needs manual escaping + # (see https://jinja.palletsprojects.com/en/2.11.x/templates/#html-escaping). + # + # * server_name: the homeserver's name. + # + # * HTML page which notifies the user that they are authenticating to confirm + # an operation on their account during the user interactive authentication + # process: 'sso_auth_confirm.html'. + # + # When rendering, this template is given the following variables: + # * redirect_url: the URL the user is about to be redirected to. Needs + # manual escaping (see + # https://jinja.palletsprojects.com/en/2.11.x/templates/#html-escaping). + # + # * description: the operation which the user is being asked to confirm + # + # * HTML page shown after a successful user interactive authentication session: + # 'sso_auth_success.html'. + # + # Note that this page must include the JavaScript which notifies of a successful authentication + # (see https://matrix.org/docs/spec/client_server/r0.6.0#fallback). + # + # This template has no additional variables. + # + # * HTML page shown after a user-interactive authentication session which + # does not map correctly onto the expected user: 'sso_auth_bad_user.html'. + # + # When rendering, this template is given the following variables: + # * server_name: the homeserver's name. + # * user_id_to_verify: the MXID of the user that we are trying to + # validate. + # + # * HTML page shown during single sign-on if a deactivated user (according to Synapse's database) + # attempts to login: 'sso_account_deactivated.html'. + # + # This template has no additional variables. + # + # * HTML page to display to users if something goes wrong during the + # OpenID Connect authentication process: 'sso_error.html'. + # + # When rendering, this template is given two variables: + # * error: the technical name of the error + # * error_description: a human-readable message for the error + # + # You can see the default templates at: + # https://github.com/matrix-org/synapse/tree/master/synapse/res/templates + # + template_dir: "${SSO_TEMPLATE_DIR:?}" + + +# JSON web token integration. The following settings can be used to make +# Synapse JSON web tokens for authentication, instead of its internal +# password database. +# +# Each JSON Web Token needs to contain a "sub" (subject) claim, which is +# used as the localpart of the mxid. +# +# Additionally, the expiration time ("exp"), not before time ("nbf"), +# and issued at ("iat") claims are validated if present. +# +# Note that this is a non-standard login type and client support is +# expected to be non-existent. +# +# See https://github.com/matrix-org/synapse/blob/master/docs/jwt.md. +# +#jwt_config: + # Uncomment the following to enable authorization using JSON web + # tokens. Defaults to false. + # + #enabled: true + + # This is either the private shared secret or the public key used to + # decode the contents of the JSON web token. + # + # Required if 'enabled' is true. + # + #secret: "provided-by-your-issuer" + + # The algorithm used to sign the JSON web token. + # + # Supported algorithms are listed at + # https://pyjwt.readthedocs.io/en/latest/algorithms.html + # + # Required if 'enabled' is true. + # + #algorithm: "provided-by-your-issuer" + + # The issuer to validate the "iss" claim against. + # + # Optional, if provided the "iss" claim will be required and + # validated for all JSON web tokens. + # + #issuer: "provided-by-your-issuer" + + # A list of audiences to validate the "aud" claim against. + # + # Optional, if provided the "aud" claim will be required and + # validated for all JSON web tokens. + # + # Note that if the "aud" claim is included in a JSON web token then + # validation will fail without configuring audiences. + # + #audiences: + # - "provided-by-your-issuer" + + +password_config: + # Uncomment to disable password login + # + #enabled: false + + # Uncomment to disable authentication against the local password + # database. This is ignored if \`enabled\` is false, and is only useful + # if you have other password_providers. + # + #localdb_enabled: false + + # Uncomment and change to a secret random string for extra security. + # DO NOT CHANGE THIS AFTER INITIAL SETUP! + # + #pepper: "EVEN_MORE_SECRET" + + # Define and enforce a password policy. Each parameter is optional. + # This is an implementation of MSC2000. + # + policy: + # Whether to enforce the password policy. + # Defaults to 'false'. + # + #enabled: true + + # Minimum accepted length for a password. + # Defaults to 0. + # + #minimum_length: 15 + + # Whether a password must contain at least one digit. + # Defaults to 'false'. + # + #require_digit: true + + # Whether a password must contain at least one symbol. + # A symbol is any character that's not a number or a letter. + # Defaults to 'false'. + # + #require_symbol: true + + # Whether a password must contain at least one lowercase letter. + # Defaults to 'false'. + # + #require_lowercase: true + + # Whether a password must contain at least one lowercase letter. + # Defaults to 'false'. + # + #require_uppercase: true + +ui_auth: + # The number of milliseconds to allow a user-interactive authentication + # session to be active. + # + # This defaults to 0, meaning the user is queried for their credentials + # before every action, but this can be overridden to alow a single + # validation to be re-used. This weakens the protections afforded by + # the user-interactive authentication process, by allowing for multiple + # (and potentially different) operations to use the same validation session. + # + # Uncomment below to allow for credential validation to last for 15 + # seconds. + # + #session_timeout: 15000 + + +# Configuration for sending emails from Synapse. +# +email: + # The hostname of the outgoing SMTP server to use. Defaults to 'localhost'. + # + smtp_host: "${SMTP_HOST:?}" + + # The port on the mail server for outgoing SMTP. Defaults to 25. + # + smtp_port: ${SMTP_PORT:?} + + # Username/password for authentication to the SMTP server. By default, no + # authentication is attempted. + # + smtp_user: "$SMTP_USER" + smtp_pass: "$SMTP_PASSWORD" + + # Uncomment the following to require TLS transport security for SMTP. + # By default, Synapse will connect over plain text, and will then switch to + # TLS via STARTTLS *if the SMTP server supports it*. If this option is set, + # Synapse will refuse to connect unless the server supports STARTTLS. + # + require_transport_security: ${SMTP_USE_STARTTLS:?} + + # notif_from defines the "From" address to use when sending emails. + # It must be set if email sending is enabled. + # + # The placeholder '%(app)s' will be replaced by the application name, + # which is normally 'app_name' (below), but may be overridden by the + # Matrix client application. + # + # Note that the placeholder must be written '%(app)s', including the + # trailing 's'. + # + notif_from: "${NOTIFICATION_FROM:?}" + + # app_name defines the default value for '%(app)s' in notif_from and email + # subjects. It defaults to 'Matrix'. + # + #app_name: my_branded_matrix_server + + # Uncomment the following to enable sending emails for messages that the user + # has missed. Disabled by default. + # + enable_notifs: ${ENABLE_NOTIFICATIONS:?} + + # Uncomment the following to disable automatic subscription to email + # notifications for new users. Enabled by default. + # + #notif_for_new_users: false + + # Custom URL for client links within the email notifications. By default + # links will be based on "https://matrix.to". + # + # (This setting used to be called riot_base_url; the old name is still + # supported for backwards-compatibility but is now deprecated.) +EOF + +if [ -n "$WEB_CLIENT_URL" ]; then + echo " client_base_url: \"$WEB_CLIENT_URL\"" +fi + +cat << EOF + # Configure the time that a validation email will expire after sending. + # Defaults to 1h. + # + #validation_token_lifetime: 15m + + # The web client location to direct users to during an invite. This is passed + # to the identity server as the org.matrix.web_client_location key. Defaults + # to unset, giving no guidance to the identity server. + # + #invite_client_location: https://app.element.io + + # Directory in which Synapse will try to find the template files below. + # If not set, or the files named below are not found within the template + # directory, default templates from within the Synapse package will be used. + # + # Synapse will look for the following templates in this directory: + # + # * The contents of email notifications of missed events: 'notif_mail.html' and + # 'notif_mail.txt'. + # + # * The contents of account expiry notice emails: 'notice_expiry.html' and + # 'notice_expiry.txt'. + # + # * The contents of password reset emails sent by the homeserver: + # 'password_reset.html' and 'password_reset.txt' + # + # * An HTML page that a user will see when they follow the link in the password + # reset email. The user will be asked to confirm the action before their + # password is reset: 'password_reset_confirmation.html' + # + # * HTML pages for success and failure that a user will see when they confirm + # the password reset flow using the page above: 'password_reset_success.html' + # and 'password_reset_failure.html' + # + # * The contents of address verification emails sent during registration: + # 'registration.html' and 'registration.txt' + # + # * HTML pages for success and failure that a user will see when they follow + # the link in an address verification email sent during registration: + # 'registration_success.html' and 'registration_failure.html' + # + # * The contents of address verification emails sent when an address is added + # to a Matrix account: 'add_threepid.html' and 'add_threepid.txt' + # + # * HTML pages for success and failure that a user will see when they follow + # the link in an address verification email sent when an address is added + # to a Matrix account: 'add_threepid_success.html' and + # 'add_threepid_failure.html' + # + # You can see the default templates at: + # https://github.com/matrix-org/synapse/tree/master/synapse/res/templates + # + #template_dir: "res/templates" + + # Subjects to use when sending emails from Synapse. + # + # The placeholder '%(app)s' will be replaced with the value of the 'app_name' + # setting above, or by a value dictated by the Matrix client application. + # + # If a subject isn't overridden in this configuration file, the value used as + # its example will be used. + # + #subjects: + + # Subjects for notification emails. + # + # On top of the '%(app)s' placeholder, these can use the following + # placeholders: + # + # * '%(person)s', which will be replaced by the display name of the user(s) + # that sent the message(s), e.g. "Alice and Bob". + # * '%(room)s', which will be replaced by the name of the room the + # message(s) have been sent to, e.g. "My super room". + # + # See the example provided for each setting to see which placeholder can be + # used and how to use them. + # + # Subject to use to notify about one message from one or more user(s) in a + # room which has a name. + #message_from_person_in_room: "[%(app)s] You have a message on %(app)s from %(person)s in the %(room)s room..." + # + # Subject to use to notify about one message from one or more user(s) in a + # room which doesn't have a name. + #message_from_person: "[%(app)s] You have a message on %(app)s from %(person)s..." + # + # Subject to use to notify about multiple messages from one or more users in + # a room which doesn't have a name. + #messages_from_person: "[%(app)s] You have messages on %(app)s from %(person)s..." + # + # Subject to use to notify about multiple messages in a room which has a + # name. + #messages_in_room: "[%(app)s] You have messages on %(app)s in the %(room)s room..." + # + # Subject to use to notify about multiple messages in multiple rooms. + #messages_in_room_and_others: "[%(app)s] You have messages on %(app)s in the %(room)s room and others..." + # + # Subject to use to notify about multiple messages from multiple persons in + # multiple rooms. This is similar to the setting above except it's used when + # the room in which the notification was triggered has no name. + #messages_from_person_and_others: "[%(app)s] You have messages on %(app)s from %(person)s and others..." + # + # Subject to use to notify about an invite to a room which has a name. + #invite_from_person_to_room: "[%(app)s] %(person)s has invited you to join the %(room)s room on %(app)s..." + # + # Subject to use to notify about an invite to a room which doesn't have a + # name. + #invite_from_person: "[%(app)s] %(person)s has invited you to chat on %(app)s..." + + # Subject for emails related to account administration. + # + # On top of the '%(app)s' placeholder, these one can use the + # '%(server_name)s' placeholder, which will be replaced by the value of the + # 'server_name' setting in your Synapse configuration. + # + # Subject to use when sending a password reset email. + #password_reset: "[%(server_name)s] Password reset" + # + # Subject to use when sending a verification email to assert an address's + # ownership. + #email_validation: "[%(server_name)s] Validate your email" + + +# Password providers allow homeserver administrators to integrate +# their Synapse installation with existing authentication methods +# ex. LDAP, external tokens, etc. +# +# For more information and known implementations, please see +# https://github.com/matrix-org/synapse/blob/master/docs/password_auth_providers.md +# +# Note: instances wishing to use SAML or CAS authentication should +# instead use the \`saml2_config\` or \`cas_config\` options, +# respectively. +# +password_providers: +# # Example config for an LDAP auth provider +# - module: "ldap_auth_provider.LdapAuthProvider" +# config: +# enabled: true +# uri: "ldap://ldap.example.com:389" +# start_tls: true +# base: "ou=users,dc=example,dc=com" +# attributes: +# uid: "cn" +# mail: "email" +# name: "givenName" +# #bind_dn: +# #bind_password: +# #filter: "(objectClass=posixAccount)" +EOF + +if [ -n "$ENABLE_LDAP_AUTH" ]; then + cat <.html') and a success page (success.html). +# +# 'version' specifies the 'current' version of the policy document. It defines +# the version to be served by the consent resource if there is no 'v' +# parameter. +# +# 'server_notice_content', if enabled, will send a user a "Server Notice" +# asking them to consent to the privacy policy. The 'server_notices' section +# must also be configured for this to work. Notices will *not* be sent to +# guest users unless 'send_server_notice_to_guests' is set to true. +# +# 'block_events_error', if set, will block any attempts to send events +# until the user consents to the privacy policy. The value of the setting is +# used as the text of the error. +# +# 'require_at_registration', if enabled, will add a step to the registration +# process, similar to how captcha works. Users will be required to accept the +# policy before their account is created. +# +# 'policy_name' is the display name of the policy users will see when registering +# for an account. Has no effect unless \`require_at_registration\` is enabled. +# Defaults to "Privacy Policy". +# +#user_consent: +# template_dir: res/templates/privacy +# version: 1.0 +# server_notice_content: +# msgtype: m.text +# body: >- +# To continue using this homeserver you must review and agree to the +# terms and conditions at %(consent_uri)s +# send_server_notice_to_guests: true +# block_events_error: >- +# To continue using this homeserver you must review and agree to the +# terms and conditions at %(consent_uri)s +# require_at_registration: false +# policy_name: Privacy Policy +# + + + +# Local statistics collection. Used in populating the room directory. +# +# 'bucket_size' controls how large each statistics timeslice is. It can +# be defined in a human readable short form -- e.g. "1d", "1y". +# +# 'retention' controls how long historical statistics will be kept for. +# It can be defined in a human readable short form -- e.g. "1d", "1y". +# +# +#stats: +# enabled: true +# bucket_size: 1d +# retention: 1y + + +# Server Notices room configuration +# +# Uncomment this section to enable a room which can be used to send notices +# from the server to users. It is a special room which cannot be left; notices +# come from a special "notices" user id. +# +# If you uncomment this section, you *must* define the system_mxid_localpart +# setting, which defines the id of the user which will be used to send the +# notices. +# +# It's also possible to override the room name, the display name of the +# "notices" user, and the avatar for the user. +# +#server_notices: +# system_mxid_localpart: notices +# system_mxid_display_name: "Server Notices" +# system_mxid_avatar_url: "mxc://server.com/oumMVlgDnLYFaPVkExemNVVZ" +# room_name: "Server Notices" +EOF + +if [ -n "$ENABLE_SERVER_NOTICES" ]; then + cat << EOF +server_notices: + system_mxid_localpart: notices + system_mxid_display_name: "Server Notices" + #system_mxid_avatar_url: "mxc://server.com/oumMVlgDnLYFaPVkExemNVVZ" + room_name: "Server Notices" +EOF +fi + +cat << EOF +# Uncomment to disable searching the public room list. When disabled +# blocks searching local and remote room lists for local and remote +# users by always returning an empty list for all queries. +# +#enable_room_list_search: false + +# The \`alias_creation\` option controls who's allowed to create aliases +# on this server. +# +# The format of this option is a list of rules that contain globs that +# match against user_id, room_id and the new alias (fully qualified with +# server name). The action in the first rule that matches is taken, +# which can currently either be "allow" or "deny". +# +# Missing user_id/room_id/alias fields default to "*". +# +# If no rules match the request is denied. An empty list means no one +# can create aliases. +# +# Options for the rules include: +# +# user_id: Matches against the creator of the alias +# alias: Matches against the alias being created +# room_id: Matches against the room ID the alias is being pointed at +# action: Whether to "allow" or "deny" the request if the rule matches +# +# The default is: +# +#alias_creation_rules: +# - user_id: "*" +# alias: "*" +# room_id: "*" +# action: allow + +# The \`room_list_publication_rules\` option controls who can publish and +# which rooms can be published in the public room list. +# +# The format of this option is the same as that for +# \`alias_creation_rules\`. +# +# If the room has one or more aliases associated with it, only one of +# the aliases needs to match the alias rule. If there are no aliases +# then only rules with \`alias: *\` match. +# +# If no rules match the request is denied. An empty list means no one +# can publish rooms. +# +# Options for the rules include: +# +# user_id: Matches against the creator of the alias +# room_id: Matches against the room ID being published +# alias: Matches against any current local or canonical aliases +# associated with the room +# action: Whether to "allow" or "deny" the request if the rule matches +# +# The default is: +# +#room_list_publication_rules: +# - user_id: "*" +# alias: "*" +# room_id: "*" +# action: allow + + +# Server admins can define a Python module that implements extra rules for +# allowing or denying incoming events. In order to work, this module needs to +# override the methods defined in synapse/events/third_party_rules.py. +# +# This feature is designed to be used in closed federations only, where each +# participating server enforces the same rules. +# +#third_party_event_rules: +# module: "my_custom_project.SuperRulesSet" +# config: +# example_option: 'things' + + +## Opentracing ## + +# These settings enable opentracing, which implements distributed tracing. +# This allows you to observe the causal chains of events across servers +# including requests, key lookups etc., across any server running +# synapse or any other other services which supports opentracing +# (specifically those implemented with Jaeger). +# +opentracing: + # tracing is disabled by default. Uncomment the following line to enable it. + # + #enabled: true + + # The list of homeservers we wish to send and receive span contexts and span baggage. + # See docs/opentracing.rst + # This is a list of regexes which are matched against the server_name of the + # homeserver. + # + # By default, it is empty, so no servers are matched. + # + #homeserver_whitelist: + # - ".*" + + # Jaeger can be configured to sample traces at different rates. + # All configuration options provided by Jaeger can be set here. + # Jaeger's configuration mostly related to trace sampling which + # is documented here: + # https://www.jaegertracing.io/docs/1.13/sampling/. + # + #jaeger_config: + # sampler: + # type: const + # param: 1 + + # Logging whether spans were started and reported + # + # logging: + # false + + +## Workers ## + +# Disables sending of outbound federation transactions on the main process. +# Uncomment if using a federation sender worker. +# +send_federation: ${SEND_FEDERATION_FROM_MAIN_PROCESS:?} + +# It is possible to run multiple federation sender workers, in which case the +# work is balanced across them. +# +# This configuration must be shared between all federation sender workers, and if +# changed all federation sender workers must be stopped at the same time and then +# started, to ensure that all instances are running with the same config (otherwise +# events may be dropped). +# +#federation_sender_instances: +# - federation_sender1 +EOF + +if [ -n "$FEDERATION_SENDER_INSTANCES" ]; then + echo "federation_sender_instances:" + for instance in $FEDERATION_SENDER_INSTANCES; do + echo " - $instance" + done +fi + +cat << EOF +# When using workers this should be a map from \`worker_name\` to the +# HTTP replication listener of the worker, if configured. +# +#instance_map: +# worker1: +# host: localhost +# port: 8034 + +# Experimental: When using workers you can define which workers should +# handle event persistence and typing notifications. Any worker +# specified here must also be in the \`instance_map\`. +# +#stream_writers: +# events: worker1 +# typing: worker1 + +# The worker that is used to run background tasks (e.g. cleaning up expired +# data). If not provided this defaults to the main process. +# +EOF + +if [ -n "$BACKGROUND_TASKS_WORKER" ]; then + echo "run_background_tasks_on: ${BACKGROUND_TASKS_WORKER:?}" +fi + +cat << EOF +# A shared secret used by the replication APIs to authenticate HTTP requests +# from workers. +# +# By default this is unused and traffic is not authenticated. +# +worker_replication_secret: "$WORKER_REPLICATION_SECRET" + + +# Configuration for Redis when using workers. This *must* be enabled when +# using workers (unless using old style direct TCP configuration). +# +redis: + # Uncomment the below to enable Redis support. + # + enabled: ${ENABLE_REDIS_SUPPORT:?} + + # Optional host and port to use to connect to redis. Defaults to + # localhost and 6379 + # + #host: localhost + #port: 6379 + + # Optional password if configured on the Redis instance + # +EOF diff --git a/type/__matrix_synapse/files/log.config.sh b/type/__matrix_synapse/files/log.config.sh new file mode 100755 index 0000000..42502ec --- /dev/null +++ b/type/__matrix_synapse/files/log.config.sh @@ -0,0 +1,70 @@ +#!/bin/sh + +cat << EOF +############################################################### +# THIS FILE HAS BEEN GENERATED BY CDIST. DO NOT EDIT BY HAND. # +############################################################### + + +# Log configuration for Synapse. +# +# This is a YAML file containing a standard Python logging configuration +# dictionary. See [1] for details on the valid settings. +# +# Synapse also supports structured logging for machine readable logs which can +# be ingested by ELK stacks. See [2] for details. +# +# [1]: https://docs.python.org/3.7/library/logging.config.html#configuration-dictionary-schema +# [2]: https://github.com/matrix-org/synapse/blob/master/docs/structured_logging.md +# +version: 1 + +formatters: + precise: + format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s- %(message)s' + +filters: + context: + (): synapse.util.logcontext.LoggingContextFilter + request: "" + +handlers: + file: + class: logging.handlers.TimedRotatingFileHandler + formatter: precise + filename: ${LOG_DIR:?}/homeserver.log + when: midnight + backupCount: 3 # Does not include the current log file. + filters: [context] + encoding: utf8 + # Default to buffering writes to log file for efficiency. This means that + # will be a delay for INFO/DEBUG logs to get written, but WARNING/ERROR + # logs will still be flushed immediately. + buffer: + class: logging.handlers.MemoryHandler + target: file + # The capacity is the number of log lines that are buffered before + # being written to disk. Increasing this will lead to better + # performance, at the expensive of it taking longer for log lines to + # be written to disk. + capacity: 10 + flushLevel: 30 # Flush for WARNING logs as well + console: + class: logging.StreamHandler + formatter: precise + level: WARN + +loggers: + synapse: + level: INFO + synapse.storage.SQL: + # beware: increasing this to DEBUG will make synapse log sensitive + # information such as access tokens. + level: INFO + twisted: + level: INFO + +root: + level: INFO + handlers: [buffer, console] +EOF diff --git a/type/__matrix_synapse/gencode-remote b/type/__matrix_synapse/gencode-remote new file mode 100755 index 0000000..30770ed --- /dev/null +++ b/type/__matrix_synapse/gencode-remote @@ -0,0 +1,35 @@ +#!/bin/sh + +os=$(cat "$__global/explorer/os") +init=$(cat "$__global/explorer/init") + +case "$os" in + alpine) + synapse_conf_dir=/etc/synapse + synapse_service=synapse + ;; + debian|ubuntu) + synapse_conf_dir=/etc/matrix-synapse + synapse_service=matrix-synapse + ;; + *) + echo "Unknown OS $os." >&2 + exit 1 + ;; +esac + +if grep -qE "^__file$synapse_conf_dir" "${__messages_in}"; then + case "$init" in + systemd) + echo "systemctl restart $synapse_service" + ;; + initd) + echo "service --ifstopped $synapse_service start" + echo "service --ifstarted $synapse_service restart" + ;; + *) + echo "Unknown init $init." >&2 + exit 1 + ;; + esac +fi diff --git a/type/__matrix_synapse/man.rst b/type/__matrix_synapse/man.rst new file mode 100644 index 0000000..0ec7a94 --- /dev/null +++ b/type/__matrix_synapse/man.rst @@ -0,0 +1,366 @@ +cdist-type__matrix_synapse(7) +============================= + +NAME +---- +cdist-type__matrix_synapse - Install and configure Synapse, a Matrix homeserver + + +DESCRIPTION +----------- +This type installs and configures the Synapse Matrix homeserver. This is a +signleton type. + + +REQUIRED PARAMETERS +------------------- +server-name + Name of your homeserver (e.g. ungleich.ch) used as part of your MXIDs. This + value cannot be changed later on. + +base-url + Public URL of your homeserver (e.g. ``_). + +database-engine + 'sqlite3' or 'psycopg2' (= Postgresql). + +database-name + Path to database file if SQLite3 is used or database name if PostgresSQL is + used. + +OPTIONAL PARAMETERS +------------------- +database-host + Database node address, only used with PostgresSQL. + +database-user + Database user, only used with PostgresSQL. + +database-password + Database password, only used with PostgresSQL. + +database-connection-pool-min + The minimum number of connections in pool, defaults to 3. + +database-connection-pool-max + The maximum number of connections in pool, defaults to 5. + +ldap-uri + Address of your LDAP server. + +ldap-base-dn + Base DN of your LDAP tree. + +ldap-uid-attribute + LDAP attribute mapping to Synapse's uid field, default to uid. + +ldap-mail-attribute + LDAP attribute mapping to Synapse's mail field, default to mail. + +ldap-name-attribute + LDAP attribute mapping to Synapse's name field, default to givenName. + +ldap-bind-dn + User used to authenticate against your LDAP server in 'search' mode. + +ldap-bind-password + Password used to authenticate against your LDAP server in 'search' mode. + +ldap-filter + LDAP user filter, defaulting to `(objectClass=posixAccount)`. + +tls-cert + Path to PEM-encoded X509 TLS certificate. Not needed if TLS termination is + handled by a reverse Proxy such as NGINX. + +tls-private-key + Path to PEM-encoded TLS private key. Not needed if TLS termination is + handled by a reverse Proxy such as NGINX. + +smtp-host + The hostname of the outgoing SMTP server to use. Defaults to 'localhost'. + +smtp-port + The port on the mail server for outgoing SMTP. Defaults to 25. + +smtp-user + Username for authentication to the SMTP server. By + default, no authentication is attempted. + +smtp-password + Password for authentication to the SMTP server. By + default, no authentication is attempted. + +notification-from + From address to use when sending emails. Defaults + to "%(app)s ". + +message-max-lifetime + Default retention policy. If set, Synapse will apply it to rooms that lack + the 'm.room.retention' state event. Ignored if + enable-message-retention-policy is not set. Defaults to 1y. + +web-client-url + Custom URL for client links within the email + notifications. By default links will be based on + "https://matrix.to". + +global-cache-factor + Controls the global cache factor, which is the default cache factor for all + caches if a specific factor for that cache is not otherwise set. Defaults to + 0.5, which will half the size of all caches. + +event-cache-size + The number of events to cache in memory. Not affected by + caches.global_factor. Defaults to 10K. + +remote-room-complexity-threshold + The limit above which rooms cannot be joined when + limit-remote-room-complexity is set. Room complexity is an arbitrary measure + based on factors such as the number of users in the room. The default is 1.0. + +room-encrypt-policy + Controls whether locally-created rooms should be end-to-end encrypted by + default. Possible options are "all" (any locally-created room), "invite" + (any room created with the private_chat or trusted_private_chat room + creation presets , and "off" (this option will take no effect). Defaults to + "off". + +turn-uri + URI to TURN server, can be provided multiple times if there is more than one + server. + +turn-shared-secret + Shared secret used to access the TURN REST API. + +turn-username + Username used to authenticate against the TURN server if needed / a shared + secret token is not used. + +turn-password + Password used to authenticate against the TURN server if needed / a shared + secret token is not used. + +turn-user-lifetime + Lifetime of TURN credentials. Defaults to 1h. + +max-upload-size + Maximum size for user-uploaded files. Defaults to 10M. + +rc-message-per-second + Message rate-limiting (per second). Defaults to 0.17. + +rc-message-burst + Message rate-limiting (burst). Defaults to 3. + +rc-login-per-second + Login rate-limiting (per-second). Defaults to 0.17. + +rc-login-burst + Login rate-limiting (burst). Defaults to 3. + +registration-allows-email-pattern + Only allow email addresses matching specified filter. Can be specified multiple times. A pattern must look like `.*@vector\.im`. + +disable-displayname-changes + Whether users are allowed to change their displayname after it has been initially set. + +disable-3pid-changes + Whether users can change the 3PIDs associated with their accounts (email address and msisdn). + +auto-join-room + Room where newly-registered users are automatically added. Can be specified multiple times. + +app-service-config-file + Path (on remote) of an application service configuration file to load. Can be specified multiple times. + +worker-replication-secret + A shared secret used by the replication APIs to authenticate HTTP requests + from workers. Ignored if worker-mode is not set. By default this is unused and + traffic is not authenticated. + +background-tasks-worker + The worker that is used to run background tasks (e.g. cleaning up expired + data). If not provided this defaults to the main process. + +outbound-federation-worker + Worker to be used for sending federation requests. Can be specified multiple + times. Disables sending outbound federation requests from the master process. + +registration-shared-secret + If set, allows registration of standard or admin accounts by anyone who + has the shared secret, even if registration is otherwise disabled. + +bind-address + Address used to bind the synapse listeners. Can be specified multiple times. + Defaults to '::1' and '127.0.0.1'. + +saml2-idp-metadata-url + HTTP(S) url to SAML2 Identity Provider (IdP), used for Single Sign On (SSO) logic. + +saml2-sp-key + Path to PEM-formatted key file for use by PySAML2. + +saml2-sp-cert + Path to PEM-formatted cert file for use by PySAML2. + +saml2-mapping-provider-module + Name of custom Python module used to map SAML2 attributes to synapse internals. + +saml2-mapping-provider-extra-settings + Extra YAML-formatted key/pair values provided as configuration to the SAML2 + mapping provider module (e.g. 'key: value'). Can be specified multiple times. + +sso-template-dir + Directory used to source SSO-related HTML templates. + +extra-setting + Arbitrary string to be added to the configuration file. Can be specified multiple times. + +BOOLEAN PARAMETERS +------------------ +enable-registrations + Enables user registration on the homeserver. + +enable-ldap-auth + Enables ldap-backed authentication. + +ldap-use-starttls + Use STARTTLS when connection to the LDAP server. + +report-stats + Whether or not to report anonymized homeserver usage statistics. + +expose-metrics + Expose metrics endpoint for Prometheus. + +enable-notifications + Enable mail notifications (see smtp-* optinal parameters). + +smtp-use-starttls + Use STARTTLS when connection to the SMTP server. + +disable-federation + Disable federation to the broader matrix network. + +registration-require-email + Make email a required field on registration. + +allow-public-rooms-over-federation + Allow other homeservers to fetch this server's public room directory. + +allow-public-rooms-without-auth + If set to 'false', requires authentication to access the server's public rooms directory through the client API. + +enable-server-notices + Enable the server notices room. + +enable-3pid-lookups + Enable 3PIDs lookup requests to identity servers from this server. + +allow-guest-access + Allows users to register as guests without a password/email/etc, and + participate in rooms hosted on this server which have been made accessible + to anonymous users. + +limit-remote-room-complexity + When this is enabled, the room "complexity" will be checked before a user joins + a new remote room. If it is above the complexity limit (see + remote-room-complexity-threshold parameter), the server will disallow + joining, or will instantly leave. + +disable-presence + Disable presence tracking on this homeserver. + +user-directory-search-all-users + Defines whether to search all users visible to your HS when searching the + user directory, rather than limiting to users visible in public rooms. + If you set it True, you'll have to rebuild the user_directory search indexes, + see + ``_. + +enable-message-retention-policy + If this feature is enabled, Synapse will regularly look for and purge events + which are older than the room's maximum retention period. Synapse will also + filter events received over federation so that events that should have been + purged are ignored and not stored again. See message-max-lifetime flag. + +worker-mode + For small instances it recommended to run Synapse in the default monolith + mode. For larger instances where performance is a concern it can be helpful + to split out functionality into multiple separate python processes. These + processes are called 'workers'. Please read the WORKER MODE section of this + manpage before enabling, as extra work and considerations are required. + +PERFORMANCE +----------- + +The Synapse server is not very performant (initial implementation, pretty +resource hungry, etc.) and will eventually be replaced by Dendrite. The +following parameters (see above descriptions) will help you with performance +tuning: + + * global-cache-factor + * event-cache-size + * disable-presence + * limit-remote-room-complexity and remote-room-complexity-threshold + +WORKER MODE +----------- + +Worker mode allows to move some processing out of the main synapse process for +horizontal scaling. You are expected to use the +`cdist-type__matrix_synapse_worker(7) +`_ type to set up workers when the +worker-mode flag is set. + +Worker mode depend on the following components: + + * A working `redis `_ server + * The hiredis python package (`python3-hiredis + `_ on debian, not + packaged in alpine as of 2021-02-17). + * The txredisapi python package, which is not packaged on debian nor alpine + as of 2021-02-17. + +The current way to install the above two python packages (if not packaged in +your distribution) is sadly to use pip (see `cdist-type__python_pip(7) +`_ core cdist type). + +It is also recommended to first take a look at: + + - `upstream's high-level overview on workers (matrix.org blog post) `_ + - `upstream's documentation on workers `_ + +EXAMPLES +-------- + +.. code-block:: sh + + __matrix_synapse --server-name ungleich.ch \ + --base-url https://matrix.ungleich.ch \ + --database-engine sqlite3 \ + --database-name /var/lib/matrix-syanpse/homeserver.db + +You might also be interested in ungleich's `__ungleich_matrix +`_ +meta-type. + +SEE ALSO +-------- +- `cdist-type__matrix_element(7) `_ +- `cdist-type__matrix_synapse_admin(7) `_ +- `cdist-type__matrix_synapse_worker(7) `_ + + +AUTHORS +------- +Timothée Floure + + +COPYING +------- +Copyright \(C) 2019-2021 Timothée Floure. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__matrix_synapse/manifest b/type/__matrix_synapse/manifest new file mode 100755 index 0000000..bc76143 --- /dev/null +++ b/type/__matrix_synapse/manifest @@ -0,0 +1,413 @@ +#!/bin/sh -e +# +# 2019 Timothée Floure (timothee.floure@ungleich.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# OS-specific configuration. +os=$(cat "$__global/explorer/os") + +case "$os" in + debian|ubuntu) + synapse_user=matrix-synapse + synapse_pkg=matrix-synapse-py3 + synapse_service=matrix-synapse + ldap_auth_provider_pkg=matrix-synapse-ldap3 + synapse_conf_dir='/etc/matrix-synapse' + synapse_data_dir='/var/lib/matrix-synapse' + + __apt_key matrix-org \ + --uri https://packages.matrix.org/debian/matrix-org-archive-keyring.gpg + + require="__apt_key/matrix-org" __apt_source matrix-org \ + --uri https://packages.matrix.org/debian/ \ + --component main + package_req="__apt_source/matrix-org" + ;; + alpine) + synapse_user=synapse + synapse_pkg=synapse + synapse_service=synapse + # Note available as of writing (2021-02-15) + ldap_auth_provider_pkg= + synapse_conf_dir='/etc/synapse' + synapse_data_dir='/var/lib/synapse' + ;; + *) + printf "Your operating system (%s) is currently not supported by this type (%s)\n" "$os" "${__type##*/}" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +# Small helper used to get boolean values which can be used as-is in the +# configuration template. +get_boolean_for () { + if [ -f "$__object/parameter/${1:?}" ]; then + echo 'true' + else + echo 'false' + fi +} + +# Small helper for erroring out on invalid combinations. +is_required_when () { + value=$1 + flag=$2 + when=$3 + + if [ -z "$value" ]; then + echo "$flag is required when $when." >&2 + exit 1 + fi +} + +# Generic configuration. +export DATA_DIR=$synapse_data_dir +export LOG_DIR='/var/log/matrix-synapse' +export PIDFILE='/var/run/matrix/homeserver.pid' +export LOG_CONFIG_PATH="$synapse_conf_dir/log.yaml" +export SIGNING_KEY_PATH="$synapse_conf_dir/signin.key" + +# Base parameters. +SERVER_NAME=$(cat "$__object/parameter/server-name") +BASE_URL=$(cat "$__object/parameter/base-url") +REPORT_STATS=$(get_boolean_for 'report-stats') +MAX_UPLOAD_SIZE=$(cat "$__object/parameter/max-upload-size") +EXPOSE_METRICS=$(get_boolean_for 'expose-metrics') +WEB_CLIENT_URL=$(cat "$__object/parameter/web-client-url") +ROOM_ENCRYPTION_POLICY=$(cat "$__object/parameter/room-encryption-policy") +BIND_ADDRESSES=$(cat "$__object/parameter/bind-address") +export SERVER_NAME BASE_URL REPORT_STATS MAX_UPLOAD_SIZE EXPOSE_METRICS \ + WEB_CLIENT_URL ROOM_ENCRYPTION_POLICY BIND_ADDRESSES + +if [ -f "$__object/parameter/enable-server-notices" ]; then + export ENABLE_SERVER_NOTICES=1 +fi + +# TLS. +if [ -f "$__object/parameter/tls-cert" ]; then + TLS_CERTIFICATE_PATH=$(cat "$__object/parameter/tls-cert") + export TLS_CERTIFICATE_PATH +fi +if [ -f "$__object/parameter/tls-private-key" ]; then + TLS_PRIVATE_KEY_PATH=$(cat "$__object/parameter/tls-private-key") + export TLS_PRIVATE_KEY_PATH +fi + +# Performance flags. +GLOBAL_CACHE_FACTOR=$(cat "$__object/parameter/global-cache-factor") +EVENT_CACHE_SIZE=$(cat "$__object/parameter/event-cache-size") +export GLOBAL_CACHE_FACTOR EVENT_CACHE_SIZE + +if [ -f "$__object/parameter/disable-presence" ]; then + export USE_PRESENCE='false' +else + export USE_PRESENCE='true' +fi + +# Database configuration. +DATABASE_ENGINE=$(cat "$__object/parameter/database-engine") +DATABASE_NAME=$(cat "$__object/parameter/database-name") +DATABASE_HOST=$(cat "$__object/parameter/database-host") +DATABASE_USER=$(cat "$__object/parameter/database-user") +DATABASE_PASSWORD=$(cat "$__object/parameter/database-password") +DATABASE_CP_MIN=$(cat "$__object/parameter/database-connection-pool-min") +DATABASE_CP_MAX=$(cat "$__object/parameter/database-connection-pool-max") +export DATABASE_ENGINE DATABASE_NAME DATABASE_HOST DATABASE_USER \ + DATABASE_PASSWORD DATABASE_CP_MIN DATABASE_CP_MAX + +# LDAP-based authentication. +if [ -f "$__object/parameter/enable-ldap-auth" ]; then + ENABLE_LDAP_AUTH=$(get_boolean_for 'enable-ldap-auth') + export ENABLE_LDAP_AUTH +fi + +LDAP_FILTER=$(cat "$__object/parameter/ldap-filter") +LDAP_UID_ATTRIBUTE=$(cat "$__object/parameter/ldap-uid-attribute") +LDAP_MAIL_ATTRIBUTE=$(cat "$__object/parameter/ldap-mail-attribute") +LDAP_NAME_ATTRIBUTE=$(cat "$__object/parameter/ldap-name-attribute") +LDAP_URI=$(cat "$__object/parameter/ldap-uri") +LDAP_BASE_DN=$(cat "$__object/parameter/ldap-base-dn") +LDAP_BIND_DN=$(cat "$__object/parameter/ldap-bind-dn") +LDAP_BIND_PASSWORD=$(cat "$__object/parameter/ldap-bind-password") +LDAP_USE_STARTTLS=$(get_boolean_for 'ldap-use-starttls') +export LDAP_FILTER LDAP_UID_ATTRIBUTE LDAP_MAIL_ATTRIBUTE LDAP_NAME_ATTRIBUTE \ + LDAP_URI LDAP_BASE_DN LDAP_BIND_DN LDAP_BIND_PASSWORD LDAP_USE_STARTTLS + +# Outgoing emails (= notifications). +ENABLE_NOTIFICATIONS=$(get_boolean_for 'enable-notifications') +SMTP_HOST=$(cat "$__object/parameter/smtp-host") +SMTP_PORT=$(cat "$__object/parameter/smtp-port") +SMTP_USE_STARTTLS=$(get_boolean_for 'smtp-use-starttls') +SMTP_USER=$(cat "$__object/parameter/smtp-user") +SMTP_PASSWORD=$(cat "$__object/parameter/smtp-password") +export SMTP_HOST SMTP_PORT SMTP_USER SMTP_PASSWORD SMTP_USE_STARTTLS \ + ENABLE_NOTIFICATIONS + +if [ -f "$__object/parameter/notification-from" ]; then + NOTIFICATION_FROM=$(cat "$__object/parameter/notification-from") + export NOTIFICATION_FROM +else + export NOTIFICATION_FROM="%(app)s " +fi + +# Registrations and users. +ALLOW_GUEST_ACCESS=$(get_boolean_for 'allow-guest-access') +ENABLE_REGISTRATIONS=$(get_boolean_for 'enable-registrations') +USER_DIRECTORY_SEARCH_ALL_USERS=$(get_boolean_for 'user-directory-search-all-users') +export ALLOW_GUEST_ACCESS ENABLE_REGISTRATIONS USER_DIRECTORY_SEARCH_ALL_USERS + +if [ -f "$__object/parameter/registration-shared-secret" ]; then + REGISTRATION_SHARED_SECRET=$(cat "$__object/parameter/registration-shared-secret") + export REGISTRATION_SHARED_SECRET +fi + +if [ -f "$__object/parameter/registration-requires-email" ]; then + export REGISTRATION_REQUIRES_EMAIL=1 +fi + +ENABLE_SET_DISPLAYNAME='true' +if [ -f "$__object/parameter/disable-displayname-changes" ]; then + ENABLE_SET_DISPLAYNAME='false' +fi +export ENABLE_SET_DISPLAYNAME + +ENABLE_3PID_CHANGES='true' +if [ -f "$__object/parameter/disable-3pid-changes" ]; then + ENABLE_3PID_CHANGES='false' +fi +export ENABLE_3PID_CHANGES + +if [ -f "$__object/parameter/auto-join-room" ]; then + AUTO_JOIN_ROOMS="$(cat "$__object/parameter/auto-join-room")" + export AUTO_JOIN_ROOMS +fi + +if [ -f "$__object/parameter/registration-allows-email-pattern" ]; then + RESGISTRATION_ALLOWS_EMAIL_PATTERN=$(cat "$__object/parameter/registration-allows-email-pattern") + export RESGISTRATION_ALLOWS_EMAIL_PATTERN +fi + +if [ -f "$__object/parameter/saml2-idp-metadata-url" ]; then + # Synapse fails to start while trying to parse IDP metadata if this package + # is not installed. + __package xmlsec1 + + SAML2_IDP_METADATA_URL=$(cat "$__object/parameter/saml2-idp-metadata-url") + export SAML2_IDP_METADATA_URL +fi + +if [ -f "$__object/parameter/saml2-sp-key" ]; then + SAML2_SP_KEY=$(cat "$__object/parameter/saml2-sp-key") + export SAML2_SP_KEY +fi + +if [ -f "$__object/parameter/saml2-sp-cert" ]; then + SAML2_SP_CERT=$(cat "$__object/parameter/saml2-sp-cert") + export SAML2_SP_CERT +fi + +if [ -f "$__object/parameter/saml2-mapping-provider-module" ]; then + SAML2_MAPPING_PROVIDER_MODULE=$(cat "$__object/parameter/saml2-mapping-provider-module") + export SAML2_MAPPING_PROVIDER_MODULE +fi + +if [ -f "$__object/parameter/saml2-mapping-provider-extra-config" ]; then + SAML2_MAPPING_PROVIDER_EXTRA_CONFIG=$(cat "$__object/parameter/saml2-mapping-provider-extra-config") + export SAML2_MAPPING_PROVIDER_EXTRA_CONFIG +fi + +SSO_TEMPLATE_DIR=$(cat "$__object/parameter/sso-template-dir") +export SSO_TEMPLATE_DIR + +if [ -n "$SAML2_SP_KEY" ] && [ -z "$SAML2_SP_CERT" ]; then + echo "--saml2-sp-cert must be set if --saml2-sp-key is provided." >&2 + exit 1 +elif [ -n "$SAML2_SP_CERT" ] && [ -z "$SAML2_SP_KEY" ]; then + echo "--saml2-sp-key must be set if --saml2-sp-cert is provided." >&2 + exit 1 +fi + +if [ -f "$__object/parameter/default-identity-server" ]; then + DEFAULT_IDENTITY_SERVER=$(cat "$__object/parameter/default-identity-server") + export DEFAULT_IDENTITY_SERVER +fi + +ENABLE_3PID_LOOKUPS='false' +if [ -f "$__object/parameter/enable-3pid-lookups" ]; then + ENABLE_3PID_LOOKUPS='true' +fi +export ENABLE_3PID_LOOKUPS + +# Federation. +ALLOW_PUBLIC_ROOMS_OVER_FEDERATION=$(get_boolean_for 'allow-public-room-over-federation') +ALLOW_PUBLIC_ROOMS_WITHOUT_AUTH=$(get_boolean_for 'allow-public-rooms-without-auth') +LIMIT_REMOTE_ROOM_COMPLEXITY=$(get_boolean_for 'limit-remote-room-complexity') +REMOTE_ROOM_COMPLEXITY_THRESHOLD=$(cat "$__object/parameter/remote-room-complexity-threshold") +export ALLOW_PUBLIC_ROOMS_OVER_FEDERATION ALLOW_PUBLIC_ROOMS_WITHOUT_AUTH \ + LIMIT_REMOTE_ROOM_COMPLEXITY REMOTE_ROOM_COMPLEXITY_THRESHOLD + +if [ -f "$__object/parameter/disable-federation" ]; then + export DISABLE_FEDERATION=1 +fi + +# Message retention. +ENABLE_MESSAGE_RETENTION_POLICY=$(get_boolean_for 'enable-message-retention-policy') +MESSAGE_RETENTION_POLICY_MAX_LIFETIME=$(cat "$__object/parameter/message-max-lifetime") +MESSAGE_RETENTION_POLICY_MIN_LIFETIME=$MESSAGE_RETENTION_POLICY_MAX_LIFETIME +export ENABLE_MESSAGE_RETENTION_POLICY MESSAGE_RETENTION_POLICY_MAX_LIFETIME MESSAGE_RETENTION_POLICY_MIN_LIFETIME + +# Previews. +ENABLE_URL_PREVIEW=$(get_boolean_for 'enable-url-preview') +export ENABLE_URL_PREVIEW + +# Rate-limiting +RC_MESSAGE_PER_SECOND=$(cat "$__object/parameter/rc-message-per-second") +RC_MESSAGE_BURST=$(cat "$__object/parameter/rc-message-burst") +RC_LOGIN_PER_SECOND=$(cat "$__object/parameter/rc-login-per-second") +RC_LOGIN_BURST=$(cat "$__object/parameter/rc-login-burst") +export RC_MESSAGE_PER_SECOND RC_MESSAGE_BURST RC_LOGIN_PER_SECOND \ + RC_LOGIN_BURST + +# Application services. +if [ -f "$__object/parameter/app-service-config-file" ]; then + APP_SERVICE_CONFIG_FILES=$(cat "$__object/parameter/app-service-config-file") + export APP_SERVICE_CONFIG_FILES +fi + +# Anything that did not fit in this type's template. +if [ -f "$__object/parameter/extra-setting" ]; then + EXTRA_SETTINGS=$(cat "$__object/parameter/extra-setting") + export EXTRA_SETTINGS +fi + +# TURN server (NAT traversal for P2P calls). +TURN_USER_LIFETIME=$(cat "$__object/parameter/turn-user-lifetime") +export TURN_USER_LIFETIME + +if [ -f "$__object/parameter/turn-shared-secret" ]; then + TURN_SHARED_SECRET=$(cat "$__object/parameter/turn-shared-secret") + export TURN_SHARED_SECRET +fi + +if [ -f "$__object/parameter/turn-uri" ]; then + TURN_URIS=$(cat "$__object/parameter/turn-uri") + export TURN_URIS +fi + +if [ -f "$__object/parameter/turn-username" ]; then + TURN_USERNAME=$(cat "$__object/parameter/turn-username") + export TURN_USERNAME +fi + +if [ -f "$__object/parameter/turn-password" ]; then + TURN_PASSWORD=$(cat "$__object/parameter/turn-password") + export TURN_PASSWORD +fi + +# Worker-mode configuration. +export MAIN_LISTENER_PORT=8008 +export ENABLE_MEDIA_REPO='true' +if [ -f "$__object/parameter/outbound-federation-worker" ]; then + FEDERATION_SENDER_INSTANCES=$(cat "$__object/parameter/outbound-federation-worker") + export FEDERATION_SENDER_INSTANCES +fi +MAIN_LISTENER_RESOURCES="[federation,client]" +if [ "$EXPOSE_METRICS" = "true" ]; then + MAIN_LISTENER_RESOURCES="$(echo "$MAIN_LISTENER_RESOURCES" | tr -d ']'),metrics]" +fi +if [ -n "$FEDERATION_SENDER_INSTANCES" ]; then + export SEND_FEDERATION_FROM_MAIN_PROCESS='false' +else + export SEND_FEDERATION_FROM_MAIN_PROCESS='true' +fi +export MAIN_LISTENER_RESOURCES + +ENABLE_REPLICATION= +ENABLE_REDIS_SUPPORT='false' +WORKER_REPLICATION_SECRET=$(cat "$__object/parameter/worker-replication-secret") +BACKGROUND_TASKS_WORKER=$(cat "$__object/parameter/background-tasks-worker") +if [ -f "$__object/parameter/worker-mode" ]; then + ENABLE_REPLICATION=1 + ENABLE_REDIS_SUPPORT='true' +fi +export ENABLE_REPLICATION ENABLE_REDIS_SUPPORT WORKER_REPLICATION_SECRET \ + BACKGROUND_TASKS_WORKER + +# Error out on invalid parameter combination. +case "$DATABASE_ENGINE" in + sqlite3) + : + ;; + psycopg2) + when='database engine is psycopg2' + is_required_when "$DATABASE_HOST" '--database-host' "$when" + is_required_when "$DATABASE_USER" '--database-user' "$when" + ;; + *) + echo "Invalid database engine: $DATABASE_ENGINE." >&2 + exit 1 + ;; +esac + + +# Install OS packages. +require="$package_req" __package "$synapse_pkg" +synapse_req="__package/$synapse_pkg" + +if [ -n "$ENABLE_LDAP_AUTH" ]; then + require="$package_req" __package "$ldap_auth_provider_pkg" +fi + +# Generate and deploy configuration files. +mkdir -p "$__object/files" +"$__type/files/homeserver.yaml.sh" > "$__object/files/homeserver.yaml" +"$__type/files/log.config.sh" > "$__object/files/log.config" + +require="$synapse_req" __file "$synapse_conf_dir/homeserver.yaml" \ + --owner $synapse_user \ + --mode 600 \ + --source "$__object/files/homeserver.yaml" +require="$synapse_req" __file "$LOG_CONFIG_PATH" \ + --owner $synapse_user \ + --mode 600 \ + --source "$__object/files/log.config" + +for directory in $DATA_DIR $LOG_DIR; do + require="$synapse_req" __directory $directory \ + --state present \ + --owner $synapse_user +done + +# Make dpkg-reconfigure happy on debian-based systems. +if [ "$os" = "debian" ] || [ "$os" = "ubuntu" ]; then + require="$synapse_req" __file "$synapse_conf_dir/conf.d/server_name.yaml" \ + --owner $synapse_user \ + --source - <<- EOF + server_name: "$SERVER_NAME" + EOF + + require="$synapse_req" __file "$synapse_conf_dir/conf.d/report_stats.yaml" \ + --owner $synapse_user \ + --source - <<- EOF + report_stats: $REPORT_STATS + EOF +fi + +# Start service at boot - started/reload in gencode-remote. +require="$synapse_req" __start_on_boot $synapse_service diff --git a/type/__matrix_synapse/parameter/boolean b/type/__matrix_synapse/parameter/boolean new file mode 100644 index 0000000..54c383a --- /dev/null +++ b/type/__matrix_synapse/parameter/boolean @@ -0,0 +1,22 @@ +enable-registrations +enable-ldap-auth +report-stats +expose-metrics +enable-notifications +smtp-use-starttls +disable-federation +registration-requires-email +allow-public-rooms-over-federation +enable-server-notices +allow-guest-access +allow-public-rooms-without-auth +limit-remote-room-complexity +disable-presence +ldap-use-starttls +user-directory-search-all-users +enable-message-retention-policy +worker-mode +enable-url-preview +enable-3pid-lookups +disable-3pid-changes +disable-displayname-changes diff --git a/type/__matrix_synapse/parameter/default/background-tasks-worker b/type/__matrix_synapse/parameter/default/background-tasks-worker new file mode 100644 index 0000000..e69de29 diff --git a/type/__matrix_synapse/parameter/default/bind-address b/type/__matrix_synapse/parameter/default/bind-address new file mode 100644 index 0000000..260d4de --- /dev/null +++ b/type/__matrix_synapse/parameter/default/bind-address @@ -0,0 +1 @@ +::1 127.0.0.1 diff --git a/type/__matrix_synapse/parameter/default/database-connection-pool-max b/type/__matrix_synapse/parameter/default/database-connection-pool-max new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/type/__matrix_synapse/parameter/default/database-connection-pool-max @@ -0,0 +1 @@ +5 diff --git a/type/__matrix_synapse/parameter/default/database-connection-pool-min b/type/__matrix_synapse/parameter/default/database-connection-pool-min new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/type/__matrix_synapse/parameter/default/database-connection-pool-min @@ -0,0 +1 @@ +3 diff --git a/type/__matrix_synapse/parameter/default/database-host b/type/__matrix_synapse/parameter/default/database-host new file mode 100644 index 0000000..e69de29 diff --git a/type/__matrix_synapse/parameter/default/database-password b/type/__matrix_synapse/parameter/default/database-password new file mode 100644 index 0000000..e69de29 diff --git a/type/__matrix_synapse/parameter/default/database-user b/type/__matrix_synapse/parameter/default/database-user new file mode 100644 index 0000000..e69de29 diff --git a/type/__matrix_synapse/parameter/default/event-cache-size b/type/__matrix_synapse/parameter/default/event-cache-size new file mode 100644 index 0000000..c19807c --- /dev/null +++ b/type/__matrix_synapse/parameter/default/event-cache-size @@ -0,0 +1 @@ +10K diff --git a/type/__matrix_synapse/parameter/default/global-cache-factor b/type/__matrix_synapse/parameter/default/global-cache-factor new file mode 100644 index 0000000..2eb3c4f --- /dev/null +++ b/type/__matrix_synapse/parameter/default/global-cache-factor @@ -0,0 +1 @@ +0.5 diff --git a/type/__matrix_synapse/parameter/default/ldap-base-dn b/type/__matrix_synapse/parameter/default/ldap-base-dn new file mode 100644 index 0000000..e69de29 diff --git a/type/__matrix_synapse/parameter/default/ldap-bind-dn b/type/__matrix_synapse/parameter/default/ldap-bind-dn new file mode 100644 index 0000000..e69de29 diff --git a/type/__matrix_synapse/parameter/default/ldap-bind-password b/type/__matrix_synapse/parameter/default/ldap-bind-password new file mode 100644 index 0000000..e69de29 diff --git a/type/__matrix_synapse/parameter/default/ldap-filter b/type/__matrix_synapse/parameter/default/ldap-filter new file mode 100644 index 0000000..f760ae9 --- /dev/null +++ b/type/__matrix_synapse/parameter/default/ldap-filter @@ -0,0 +1 @@ +(objectClass=posixAccount) diff --git a/type/__matrix_synapse/parameter/default/ldap-mail-attribute b/type/__matrix_synapse/parameter/default/ldap-mail-attribute new file mode 100644 index 0000000..fa7963c --- /dev/null +++ b/type/__matrix_synapse/parameter/default/ldap-mail-attribute @@ -0,0 +1 @@ +mail diff --git a/type/__matrix_synapse/parameter/default/ldap-name-attribute b/type/__matrix_synapse/parameter/default/ldap-name-attribute new file mode 100644 index 0000000..4368fce --- /dev/null +++ b/type/__matrix_synapse/parameter/default/ldap-name-attribute @@ -0,0 +1 @@ +givenName diff --git a/type/__matrix_synapse/parameter/default/ldap-uid-attribute b/type/__matrix_synapse/parameter/default/ldap-uid-attribute new file mode 100644 index 0000000..8cd2301 --- /dev/null +++ b/type/__matrix_synapse/parameter/default/ldap-uid-attribute @@ -0,0 +1 @@ +uid diff --git a/type/__matrix_synapse/parameter/default/ldap-uri b/type/__matrix_synapse/parameter/default/ldap-uri new file mode 100644 index 0000000..e69de29 diff --git a/type/__matrix_synapse/parameter/default/max-upload-size b/type/__matrix_synapse/parameter/default/max-upload-size new file mode 100644 index 0000000..a1f4d0d --- /dev/null +++ b/type/__matrix_synapse/parameter/default/max-upload-size @@ -0,0 +1 @@ +10M diff --git a/type/__matrix_synapse/parameter/default/message-max-lifetime b/type/__matrix_synapse/parameter/default/message-max-lifetime new file mode 100644 index 0000000..4730191 --- /dev/null +++ b/type/__matrix_synapse/parameter/default/message-max-lifetime @@ -0,0 +1 @@ +1y diff --git a/type/__matrix_synapse/parameter/default/rc-login-burst b/type/__matrix_synapse/parameter/default/rc-login-burst new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/type/__matrix_synapse/parameter/default/rc-login-burst @@ -0,0 +1 @@ +3 diff --git a/type/__matrix_synapse/parameter/default/rc-login-per-second b/type/__matrix_synapse/parameter/default/rc-login-per-second new file mode 100644 index 0000000..50653ad --- /dev/null +++ b/type/__matrix_synapse/parameter/default/rc-login-per-second @@ -0,0 +1 @@ +0.17 diff --git a/type/__matrix_synapse/parameter/default/rc-message-burst b/type/__matrix_synapse/parameter/default/rc-message-burst new file mode 100644 index 0000000..00750ed --- /dev/null +++ b/type/__matrix_synapse/parameter/default/rc-message-burst @@ -0,0 +1 @@ +3 diff --git a/type/__matrix_synapse/parameter/default/rc-message-per-second b/type/__matrix_synapse/parameter/default/rc-message-per-second new file mode 100644 index 0000000..50653ad --- /dev/null +++ b/type/__matrix_synapse/parameter/default/rc-message-per-second @@ -0,0 +1 @@ +0.17 diff --git a/type/__matrix_synapse/parameter/default/remote-room-complexity-threshold b/type/__matrix_synapse/parameter/default/remote-room-complexity-threshold new file mode 100644 index 0000000..d3827e7 --- /dev/null +++ b/type/__matrix_synapse/parameter/default/remote-room-complexity-threshold @@ -0,0 +1 @@ +1.0 diff --git a/type/__matrix_synapse/parameter/default/room-encryption-policy b/type/__matrix_synapse/parameter/default/room-encryption-policy new file mode 100644 index 0000000..cfb931e --- /dev/null +++ b/type/__matrix_synapse/parameter/default/room-encryption-policy @@ -0,0 +1 @@ +off diff --git a/type/__matrix_synapse/parameter/default/smtp-host b/type/__matrix_synapse/parameter/default/smtp-host new file mode 100644 index 0000000..2fbb50c --- /dev/null +++ b/type/__matrix_synapse/parameter/default/smtp-host @@ -0,0 +1 @@ +localhost diff --git a/type/__matrix_synapse/parameter/default/smtp-password b/type/__matrix_synapse/parameter/default/smtp-password new file mode 100644 index 0000000..e69de29 diff --git a/type/__matrix_synapse/parameter/default/smtp-port b/type/__matrix_synapse/parameter/default/smtp-port new file mode 100644 index 0000000..7273c0f --- /dev/null +++ b/type/__matrix_synapse/parameter/default/smtp-port @@ -0,0 +1 @@ +25 diff --git a/type/__matrix_synapse/parameter/default/smtp-user b/type/__matrix_synapse/parameter/default/smtp-user new file mode 100644 index 0000000..e69de29 diff --git a/type/__matrix_synapse/parameter/default/sso-template-dir b/type/__matrix_synapse/parameter/default/sso-template-dir new file mode 100644 index 0000000..b51bcdc --- /dev/null +++ b/type/__matrix_synapse/parameter/default/sso-template-dir @@ -0,0 +1 @@ +res/template diff --git a/type/__matrix_synapse/parameter/default/turn-user-lifetime b/type/__matrix_synapse/parameter/default/turn-user-lifetime new file mode 100644 index 0000000..6f96dba --- /dev/null +++ b/type/__matrix_synapse/parameter/default/turn-user-lifetime @@ -0,0 +1 @@ +1h diff --git a/type/__matrix_synapse/parameter/default/web-client-url b/type/__matrix_synapse/parameter/default/web-client-url new file mode 100644 index 0000000..e69de29 diff --git a/type/__matrix_synapse/parameter/default/worker-replication-secret b/type/__matrix_synapse/parameter/default/worker-replication-secret new file mode 100644 index 0000000..e69de29 diff --git a/type/__matrix_synapse/parameter/optional b/type/__matrix_synapse/parameter/optional new file mode 100644 index 0000000..1786dd1 --- /dev/null +++ b/type/__matrix_synapse/parameter/optional @@ -0,0 +1,44 @@ +database-host +database-user +database-password +database-connection-pool-min +database-connection-pool-max +ldap-uri +ldap-base-dn +ldap-uid-attribute +ldap-mail-attribute +ldap-name-attribute +ldap-bind-dn +ldap-bind-password +ldap-filter +turn-shared-secret +turn-user-lifetime +turn-username +turn-password +max-upload-size +smtp-host +smtp-port +smtp-user +smtp-password +web-client-url +rc-message-per-second +rc-message-burst +rc-login-per-second +rc-login-burst +global-cache-factor +event-cache-size +remote-room-complexity-threshold +room-encryption-policy +notification-from +message-max-lifetime +worker-replication-secret +background-tasks-worker +tls-cert +tls-private-key +registration-shared-secret +saml2-idp-metadata-url +saml2-sp-key +saml2-sp-cert +default-identity-server +saml2-mapping-provider-module +sso-template-dir diff --git a/type/__matrix_synapse/parameter/optional_multiple b/type/__matrix_synapse/parameter/optional_multiple new file mode 100644 index 0000000..dfd69cb --- /dev/null +++ b/type/__matrix_synapse/parameter/optional_multiple @@ -0,0 +1,8 @@ +turn-uri +registration-allows-email-pattern +auto-join-room +app-service-config-file +extra-setting +bind-address +outbound-federation-worker +saml2-mapping-provider-extra-config diff --git a/type/__matrix_synapse/parameter/required b/type/__matrix_synapse/parameter/required new file mode 100644 index 0000000..f9ebcb3 --- /dev/null +++ b/type/__matrix_synapse/parameter/required @@ -0,0 +1,4 @@ +server-name +base-url +database-engine +database-name diff --git a/type/__matrix_synapse/singleton b/type/__matrix_synapse/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__matrix_synapse_worker/files/matrix-synapse-worker@.service b/type/__matrix_synapse_worker/files/matrix-synapse-worker@.service new file mode 100644 index 0000000..6f89cd8 --- /dev/null +++ b/type/__matrix_synapse_worker/files/matrix-synapse-worker@.service @@ -0,0 +1,25 @@ +[Unit] +Description=Synapse %i +AssertPathExists=/etc/matrix-synapse/workers/%i.yaml + +# This service should be restarted when the synapse target is restarted. +PartOf=matrix-synapse.target + +# if this is started at the same time as the main, let the main process start +# first, to initialise the database schema. +After=matrix-synapse.service + +[Service] +Type=notify +NotifyAccess=main +User=matrix-synapse +WorkingDirectory=/var/lib/matrix-synapse +EnvironmentFile=/etc/default/matrix-synapse +ExecStart=/opt/venvs/matrix-synapse/bin/python -m synapse.app.generic_worker --config-path=/etc/matrix-synapse/homeserver.yaml --config-path=/etc/matrix-synapse/conf.d/ --config-path=/etc/matrix-synapse/workers/%i.yaml +ExecReload=/bin/kill -HUP $MAINPID +Restart=on-failure +RestartSec=3 +SyslogIdentifier=matrix-synapse-%i + +[Install] +WantedBy=matrix-synapse.target diff --git a/type/__matrix_synapse_worker/files/worker.yaml.sh b/type/__matrix_synapse_worker/files/worker.yaml.sh new file mode 100755 index 0000000..d7303c7 --- /dev/null +++ b/type/__matrix_synapse_worker/files/worker.yaml.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +generate_bind_addresses () { + if [ -n "$WORKER_BIND_ADDRESSES" ]; then + echo "bind_addresses:" + for addr in $WORKER_BIND_ADDRESSES; do + echo " - '$addr'" + done + else + echo "bind_addresses: []" + fi +} + +cat << EOF +worker_app: "${WORKER_APP:?}" +worker_name: "${WORKER_NAME:?}" + +# The replication listener on the main synapse process. +worker_replication_host: "${WORKER_REPLICATION_HOST:?}" +worker_replication_http_port: ${WORKER_REPLICATION_PORT:?} + +worker_listeners: + - type: http + port: ${WORKER_PORT:?} + x_forwarded: true + $(generate_bind_addresses) + resources: + - names: +EOF + +for resource in ${WORKER_RESOURCES:?}; do +echo " - $resource" +done + +cat << EOF + +worker_log_config: "${WORKER_LOG_CONFIG:?}" +EOF diff --git a/type/__matrix_synapse_worker/gencode-remote b/type/__matrix_synapse_worker/gencode-remote new file mode 100755 index 0000000..9b82ad0 --- /dev/null +++ b/type/__matrix_synapse_worker/gencode-remote @@ -0,0 +1,12 @@ +#!/bin/sh + +# Designed for Debian/systemd - make sure to adapt when you add support for other +# distributions/OSs. +name=$__object_id +synapse_conf_dir='/etc/matrix-synapse' +synapse_workers_conf_dir="$synapse_conf_dir/workers" +systemd_worker_service="matrix-synapse-worker@$name" + +if grep -qE "^__file$synapse_workers_conf_dir/$name" "${__messages_in}"; then + echo "systemctl restart $systemd_worker_service" +fi diff --git a/type/__matrix_synapse_worker/man.rst b/type/__matrix_synapse_worker/man.rst new file mode 100644 index 0000000..7f9269d --- /dev/null +++ b/type/__matrix_synapse_worker/man.rst @@ -0,0 +1,83 @@ +cdist-type__matrix_synapse(7) +====================== + +NAME +---- +cdist-type__matrix_synapse_worker - Configure a synapse worker + + +DESCRIPTION +----------- +This type configures and start a matrix worker. This type does not install +synapse: `cdist-type__matrix_synapse(7) `_ +type must be run first. + +It is also recommended to take a look at: + + - `upstream's high-level overview on workers (matrix.org blog post) `_ + - `upstream's documentation on workers `_ + +REQUIRED PARAMETERS +------------------- +app + Worker application to be used. A detailed list is available on `upstream's + documentation + `_. + +port + Port on which this worker will listen. + +OPTIONAL PARAMETERS +------------------- +replication-host + Replication endpoint host of your main synapse process. Defaults to + localhost. + +replication-port + Replication endpoint port of your main synapse process. Defaults to 9093. + +log-config + Path to log configuration. Defaults to synapse's main process log + configuration. + +resource + Resources to be served by this worker. Can be specified multiple times. + Defaults to 'client' and 'federation'. + +bind-address + Address used to bind the synapse listeners. Can be specified multiple times. + Defaults to '::1' and '127.0.0.1'. + + +EXAMPLES +-------- + +.. code-block:: sh + + __matrix_synapse --server-name ungleich.ch \ + --base-url https://matrix.ungleich.ch \ + --database-engine sqlite3 \ + --database-name /var/lib/matrix-syanpse/homeserver.db \ + --worker-mode + require="__matrix_synapse" __matrix_synapse_worker generic \ + --app 'synapse.app.generic_worker' \ + --port 8083 \ + --resource 'federation' \ + --resource 'client' + +SEE ALSO +-------- +- `cdist-type__matrix_synapse(7) `_ + + +AUTHORS +------- +Timothée Floure + + +COPYING +------- +Copyright \(C) 2019-2021 Timothée Floure. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__matrix_synapse_worker/manifest b/type/__matrix_synapse_worker/manifest new file mode 100755 index 0000000..81db378 --- /dev/null +++ b/type/__matrix_synapse_worker/manifest @@ -0,0 +1,68 @@ +#!/bin/sh + +# TODO: check if matrix-synapse package is installed (fail if not - it's not +# this type's job to install it). + +name=$__object_id +os=$(cat "$__global/explorer/os") + +case "$os" in + debian) + synapse_conf_dir='/etc/matrix-synapse' + synapse_workers_conf_dir="$synapse_conf_dir/workers" + + # Synapse log configuration on debian - default value of config-log + # parameter. + WORKER_LOG_CONFIG="$synapse_conf_dir/log.yaml" + + # As of writing, debian's matrix-synapse package does not install the + # matrix-synapse-worker@.service systemd unit. + systemd_worker_service_override=present + systemd_worker_service="matrix-synapse-worker@$name" + ;; + *) + printf "Your operating system (%s) is currently not supported by this type (%s)\n" "$os" "${__type##*/}" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +# Type parameters. +WORKER_NAME=$__object_id +WORKER_APP=$(cat "$__object/parameter/app") +WORKER_PORT=$(cat "$__object/parameter/port") +WORKER_RESOURCES=$(cat "$__object/parameter/resource") +WORKER_BIND_ADDRESSES=$(cat "$__object/parameter/bind-address") +export WORKER_APP WORKER_NAME WORKER_PORT WORKER_RESOURCES WORKER_BIND_ADDRESSES + +if [ -f "$__object/parameter/log-config" ]; then + WORKER_LOG_CONFIG=$(cat "$__object/parameter/log-config") +fi +export WORKER_LOG_CONFIG + +WORKER_REPLICATION_HOST=$(cat "$__object/parameter/replication-host") +WORKER_REPLICATION_PORT=$(cat "$__object/parameter/replication-port") +export WORKER_REPLICATION_HOST WORKER_REPLICATION_PORT + +# Generate and deploy configuration files. +mkdir -p "$__object/files" +"$__type/files/worker.yaml.sh" > "$__object/files/worker.yaml" + +__directory "$synapse_workers_conf_dir" --parents +require="__directory/$synapse_workers_conf_dir" \ + __file "$synapse_workers_conf_dir/$name.yaml" \ + --source "$__object/files/worker.yaml" \ + --mode 0644 + +__file "/etc/systemd/system/matrix-synapse-worker@.service" \ + --source "$__type/files/matrix-synapse-worker@.service" \ + --mode 0644 \ + --state $systemd_worker_service_override + +# Start service, enable at boot. +service_req= +if [ "$systemd_worker_service_override" ]; then + service_req="__file/etc/systemd/system/matrix-synapse-worker@.service" +fi +require="__file/$synapse_workers_conf_dir/$name.yaml $service_req" \ + __start_on_boot "$systemd_worker_service" diff --git a/type/__matrix_synapse_worker/parameter/default/bind-address b/type/__matrix_synapse_worker/parameter/default/bind-address new file mode 100644 index 0000000..260d4de --- /dev/null +++ b/type/__matrix_synapse_worker/parameter/default/bind-address @@ -0,0 +1 @@ +::1 127.0.0.1 diff --git a/type/__matrix_synapse_worker/parameter/default/replication-host b/type/__matrix_synapse_worker/parameter/default/replication-host new file mode 100644 index 0000000..2fbb50c --- /dev/null +++ b/type/__matrix_synapse_worker/parameter/default/replication-host @@ -0,0 +1 @@ +localhost diff --git a/type/__matrix_synapse_worker/parameter/default/replication-port b/type/__matrix_synapse_worker/parameter/default/replication-port new file mode 100644 index 0000000..ed91c92 --- /dev/null +++ b/type/__matrix_synapse_worker/parameter/default/replication-port @@ -0,0 +1 @@ +9093 diff --git a/type/__matrix_synapse_worker/parameter/default/resource b/type/__matrix_synapse_worker/parameter/default/resource new file mode 100644 index 0000000..16378ec --- /dev/null +++ b/type/__matrix_synapse_worker/parameter/default/resource @@ -0,0 +1 @@ +client federation diff --git a/type/__matrix_synapse_worker/parameter/optional b/type/__matrix_synapse_worker/parameter/optional new file mode 100644 index 0000000..2f61487 --- /dev/null +++ b/type/__matrix_synapse_worker/parameter/optional @@ -0,0 +1,3 @@ +replication-host +replication-port +log-config diff --git a/type/__matrix_synapse_worker/parameter/optional_multiple b/type/__matrix_synapse_worker/parameter/optional_multiple new file mode 100644 index 0000000..d777f84 --- /dev/null +++ b/type/__matrix_synapse_worker/parameter/optional_multiple @@ -0,0 +1,2 @@ +resource +bind-address diff --git a/type/__matrix_synapse_worker/parameter/required b/type/__matrix_synapse_worker/parameter/required new file mode 100644 index 0000000..3d93f2a --- /dev/null +++ b/type/__matrix_synapse_worker/parameter/required @@ -0,0 +1,2 @@ +app +port diff --git a/type/__matterbridge/files/matterbridge.service.sh b/type/__matterbridge/files/matterbridge.service.sh new file mode 100755 index 0000000..9dbd1cb --- /dev/null +++ b/type/__matterbridge/files/matterbridge.service.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +cat <`_ + + +AUTHORS +------- +Timothée Floure + + +COPYING +------- +Copyright \(C) 2020 Timothée Floure. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__matterbridge/manifest b/type/__matterbridge/manifest new file mode 100755 index 0000000..2b5738b --- /dev/null +++ b/type/__matterbridge/manifest @@ -0,0 +1,100 @@ +#!/bin/sh -e +# +# 2020 Timothée Floure (timothee.floure@ungleich.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +os=$(cat "$__global/explorer/os") +case "$os" in + debian|ubuntu) + # This type assume systemd for service installation. + ;; + *) + printf "Your operating system (%s) is currently not supported by this type (%s)\n" "$os" "${__type##*/}" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +# Required parameters. +version=$(cat "$__object/parameter/version") +if [ -f "$__object/parameter/config" ]; then + config="$(cat "$__object/parameter/config")" + if [ "$config" = "-" ]; then + mkdir -p "$__object/files" + config="$__object/files/matterbridge.toml" + cat "$__object/stdin" > "$config" + fi +fi + +# Hardcoded values used in templates. +export BINARY_PATH=/usr/local/bin/matterbridge +export CONFIG_PATH=/etc/matterbridge/matterbridge.toml +export USER=matterbridge +export GROUP=$USER + +# Internal variables. +artefact="matterbridge-$version-linux-64bit" +checksum_file="checksums.txt" +release_download_url=https://github.com/42wim/matterbridge/releases/download +binary_url="$release_download_url/v$version/$artefact" +checksum_file_url="$release_download_url/v$version/$checksum_file" +config_dir=$(dirname $CONFIG_PATH) +systemd_unit_path='/etc/systemd/system/matterbridge.service' + +# Check if curl is available. +if ! command -v curl; then + echo "curl is required for this type, but could not be found. Exiting." >&2 + exit 1 +fi + +# Initialize working directory. +mkdir -p "$__object/files" + +# Download and check matterbridge binary. +curl -L "$binary_url" -o "$__object/files/$artefact" +curl -Ls "$checksum_file_url" | grep "$artefact" > "$__object/files/$checksum_file" +if ! (cd "$__object/files"; sha256sum --check $checksum_file); then + echo "Matterbridge binary checksum failed." >&2 + exit 1 +fi + +# Create service user. +__user $USER --home "/var/lib/$USER" + +# Deploy matterbridge binary. +require="__user/$USER" __file "$BINARY_PATH" \ + --source "$__object/files/$artefact" \ + --owner "$USER" --mode 755 + +# Generate and deploy configuration file. +"$__type/files/matterbridge.service.sh" > "$__object/files/matterbridge.service" + +require="__user/$USER" __directory "$config_dir" \ + --owner "$USER" --mode 0755 --parents \ + +require="__directory/$config_dir" __file "$CONFIG_PATH" \ + --owner "$USER" \ + --mode 0640 \ + --source "$config" + +__file "$systemd_unit_path" \ + --source "$__object/files/matterbridge.service" + +# Deal with init system. +require="__file/$systemd_unit_path" __start_on_boot matterbridge +require="__file/$BINARY_PATH __file/$CONFIG_PATH __file/$systemd_unit_path" __service matterbridge --action restart diff --git a/type/__matterbridge/parameter/required b/type/__matterbridge/parameter/required new file mode 100644 index 0000000..ed5d8b3 --- /dev/null +++ b/type/__matterbridge/parameter/required @@ -0,0 +1,2 @@ +version +config diff --git a/type/__matterbridge/singleton b/type/__matterbridge/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__netbox/explorer/secretkey b/type/__netbox/explorer/secretkey new file mode 100755 index 0000000..7cce279 --- /dev/null +++ b/type/__netbox/explorer/secretkey @@ -0,0 +1,8 @@ +#!/bin/sh -e + +# Explorer will output the key if he exists. + +secretkey="/opt/netbox/cdist/secretkey" +if [ -f "$secretkey" ]; then + cat "$secretkey" +fi diff --git a/type/__netbox/explorer/version b/type/__netbox/explorer/version new file mode 100755 index 0000000..ee3dde8 --- /dev/null +++ b/type/__netbox/explorer/version @@ -0,0 +1,5 @@ +#!/bin/sh -e + +# output version if exist +version_path="/opt/netbox/cdist/version" +if [ -f "$version_path" ]; then cat "$version_path"; fi diff --git a/type/__netbox/files/configuration.py.sh b/type/__netbox/files/configuration.py.sh new file mode 100755 index 0000000..31ebd05 --- /dev/null +++ b/type/__netbox/files/configuration.py.sh @@ -0,0 +1,319 @@ +#!/bin/sh + +cat << EOF +######################### +# # +# Required settings # +# # +######################### + +# This is a list of valid fully-qualified domain names (FQDNs) for the NetBox server. NetBox will not permit write +# access to the server via any other hostnames. The first FQDN in the list will be treated as the preferred name. +# +# Example: ALLOWED_HOSTS = ['netbox.example.com', 'netbox.internal.local'] +ALLOWED_HOSTS = [$ALLOWED_HOSTS ] + +# PostgreSQL database configuration. See the Django documentation for a complete list of available parameters: +# https://docs.djangoproject.com/en/stable/ref/settings/#databases +DATABASE = { + 'NAME': '$DATABASE_NAME', # Database name + 'USER': '$DATABASE_USER', # PostgreSQL username + 'PASSWORD': '$DATABASE_PASSWORD', # PostgreSQL password + 'HOST': '$DATABASE_HOST', # Database server + 'PORT': '$DATABASE_PORT', # Database port (leave blank for default) + 'CONN_MAX_AGE': 300, # Max database connection age +} + +# Redis database settings. Redis is used for caching and for queuing background tasks such as webhook events. A separate +# configuration exists for each. Full connection details are required in both sections, and it is strongly recommended +# to use two separate database IDs. +REDIS = { + 'tasks': { + 'HOST': '$REDIS_HOST', + 'PORT': $REDIS_PORT, + # Comment out \`HOST\` and \`PORT\` lines and uncomment the following if using Redis Sentinel + # 'SENTINELS': [('mysentinel.redis.example.com', 6379)], + # 'SENTINEL_SERVICE': 'netbox', + 'PASSWORD': '$REDIS_PASSWORD', + 'DATABASE': $((REDIS_DBID_OFFSET + 0)), + 'SSL': $REDIS_SSL, + }, + 'caching': { + 'HOST': '$REDIS_HOST', + 'PORT': $REDIS_PORT, + # Comment out \`HOST\` and \`PORT\` lines and uncomment the following if using Redis Sentinel + # 'SENTINELS': [('mysentinel.redis.example.com', 6379)], + # 'SENTINEL_SERVICE': 'netbox', + 'PASSWORD': '$REDIS_PASSWORD', + 'DATABASE': $((REDIS_DBID_OFFSET + 1)), + 'SSL': $REDIS_SSL, + } +} +RQ_DEFAULT_TIMEOUT = 300 + +# This key is used for secure generation of random numbers and strings. It must never be exposed outside of this file. +# For optimal security, SECRET_KEY should be at least 50 characters in length and contain a mix of letters, numbers, and +# symbols. NetBox will not run without this defined. For more information, see +# https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-SECRET_KEY +SECRET_KEY = '$SECRET_KEY' + + +######################### +# # +# Optional settings # +# # +######################### + +# Specify one or more name and email address tuples representing NetBox administrators. These people will be notified of +# application errors (assuming correct email settings are provided). +ADMINS = [ + # ['John Doe', 'jdoe@example.com'], +] + +# URL schemes that are allowed within links in NetBox +ALLOWED_URL_SCHEMES = ( + 'file', 'ftp', 'ftps', 'http', 'https', 'irc', 'mailto', 'sftp', 'ssh', 'tel', 'telnet', 'tftp', 'vnc', 'xmpp', +) + +# Optionally display a persistent banner at the top and/or bottom of every page. HTML is allowed. To display the same +# content in both banners, define BANNER_TOP and set BANNER_BOTTOM = BANNER_TOP. +BANNER_TOP = '' +BANNER_BOTTOM = '' + +# Text to include on the login page above the login form. HTML is allowed. +BANNER_LOGIN = '' + +# Base URL path if accessing NetBox within a directory. For example, if installed at http://example.com/netbox/, set: +# BASE_PATH = 'netbox/' +BASE_PATH = '$BASEPATH' + +# Cache timeout in seconds. Set to 0 to dissable caching. Defaults to 900 (15 minutes) +CACHE_TIMEOUT = 900 + +# Maximum number of days to retain logged changes. Set to 0 to retain changes indefinitely. (Default: 90) +CHANGELOG_RETENTION = 90 + +# API Cross-Origin Resource Sharing (CORS) settings. If CORS_ORIGIN_ALLOW_ALL is set to True, all origins will be +# allowed. Otherwise, define a list of allowed origins using either CORS_ORIGIN_WHITELIST or +# CORS_ORIGIN_REGEX_WHITELIST. For more information, see https://github.com/ottoyiu/django-cors-headers +CORS_ORIGIN_ALLOW_ALL = False +CORS_ORIGIN_WHITELIST = [ + # 'https://hostname.example.com', +] +CORS_ORIGIN_REGEX_WHITELIST = [ + # r'^(https?://)?(\w+\.)?example\.com$', +] + +# Set to True to enable server debugging. WARNING: Debugging introduces a substantial performance penalty and may reveal +# sensitive information about your installation. Only enable debugging while performing testing. Never enable debugging +# on a production system. +DEBUG = False + +# Email settings +EMAIL = { + 'SERVER': '$SMTP_HOST', + 'PORT': $SMTP_PORT, + 'USERNAME': '$SMTP_USER', + 'PASSWORD': '$SMTP_PASSWORD', + 'USE_SSL': $SMTP_USE_SSL, + 'USE_TLS': $SMTP_USE_TLS, + 'TIMEOUT': 10, # seconds + 'FROM_EMAIL': '$SMTP_FROM_EMAIL', +} + +# Enforcement of unique IP space can be toggled on a per-VRF basis. To enforce unique IP space within the global table +# (all prefixes and IP addresses not assigned to a VRF), set ENFORCE_GLOBAL_UNIQUE to True. +ENFORCE_GLOBAL_UNIQUE = False + +# Exempt certain models from the enforcement of view permissions. Models listed here will be viewable by all users and +# by anonymous users. List models in the form \`.\`. Add '*' to this list to exempt all models. +EXEMPT_VIEW_PERMISSIONS = [ + # 'dcim.site', + # 'dcim.region', + # 'ipam.prefix', +] + +EOF + +if [ "$HTTP_PROXY" != "" ] || [ "$HTTPS_PROXY" != "" ]; then + cat << EOF +# HTTP proxies NetBox should use when sending outbound HTTP requests (e.g. for webhooks). +HTTP_PROXIES = { +EOF + if [ "$HTTP_PROXY" != "" ]; then + cat << EOF + 'http': '$HTTP_PROXY', +EOF + fi + if [ "$HTTPS_PROXY" != "" ]; then + cat << EOF + 'https': '$HTTPS_PROXY', +EOF + fi + cat << EOF +} +EOF +fi + +cat << EOF +# IP addresses recognized as internal to the system. The debugging toolbar will be available only to clients accessing +# NetBox from an internal IP. +INTERNAL_IPS = ('127.0.0.1', '::1') + +# Enable custom logging. Please see the Django documentation for detailed guidance on configuring custom logs: +# https://docs.djangoproject.com/en/stable/topics/logging/ +LOGGING = {} + +# Setting this to True will permit only authenticated users to access any part of NetBox. By default, anonymous users +# are permitted to access most data in NetBox (excluding secrets) but not make any changes. +LOGIN_REQUIRED = $LOGIN_REQUIRED + +# The length of time (in seconds) for which a user will remain logged into the web UI before being prompted to +# re-authenticate. (Default: 1209600 [14 days]) +LOGIN_TIMEOUT = None + +# Setting this to True will display a "maintenance mode" banner at the top of every page. +MAINTENANCE_MODE = False + +# An API consumer can request an arbitrary number of objects =by appending the "limit" parameter to the URL (e.g. +# "?limit=1000"). This setting defines the maximum limit. Setting it to 0 or None will allow an API consumer to request +# all objects by specifying "?limit=0". +MAX_PAGE_SIZE = 1000 + +EOF + +if [ "$MEDIA_ROOT" != "" ]; then + cat << EOF +# The file path where uploaded media such as image attachments are stored. A trailing slash is not needed. Note that +# the default value of this setting is derived from the installed location. +MEDIA_ROOT = '$MEDIA_ROOT' + +EOF +fi + +cat << EOF +# By default uploaded media is stored on the local filesystem. Using Django-storages is also supported. Provide the +# class path of the storage driver in STORAGE_BACKEND and any configuration options in STORAGE_CONFIG. For example: +# STORAGE_BACKEND = 'storages.backends.s3boto3.S3Boto3Storage' +# STORAGE_CONFIG = { +# 'AWS_ACCESS_KEY_ID': 'Key ID', +# 'AWS_SECRET_ACCESS_KEY': 'Secret', +# 'AWS_STORAGE_BUCKET_NAME': 'netbox', +# 'AWS_S3_REGION_NAME': 'eu-west-1', +# } + +# Expose Prometheus monitoring metrics at the HTTP endpoint '/metrics' +METRICS_ENABLED = False + +# Credentials that NetBox will uses to authenticate to devices when connecting via NAPALM. +NAPALM_USERNAME = '' +NAPALM_PASSWORD = '' + +# NAPALM timeout (in seconds). (Default: 30) +NAPALM_TIMEOUT = 30 + +# NAPALM optional arguments (see http://napalm.readthedocs.io/en/latest/support/#optional-arguments). Arguments must +# be provided as a dictionary. +NAPALM_ARGS = {} + +# Determine how many objects to display per page within a list. (Default: 50) +PAGINATE_COUNT = 50 + +# Enable installed plugins. Add the name of each plugin to the list. +PLUGINS = [] + +# Plugins configuration settings. These settings are used by various plugins that the user may have installed. +# Each key in the dictionary is the name of an installed plugin and its value is a dictionary of settings. +# PLUGINS_CONFIG = { +# 'my_plugin': { +# 'foo': 'bar', +# 'buzz': 'bazz' +# } +# } + +# When determining the primary IP address for a device, IPv6 is preferred over IPv4 by default. Set this to True to +# prefer IPv4 instead. +PREFER_IPV4 = False + +# Rack elevation size defaults, in pixels. For best results, the ratio of width to height should be roughly 10:1. +RACK_ELEVATION_DEFAULT_UNIT_HEIGHT = 22 +RACK_ELEVATION_DEFAULT_UNIT_WIDTH = 220 + +EOF + +if [ "$USE_LDAP" ]; then + cat << EOF +# Remote authentication support with ldap +REMOTE_AUTH_ENABLED = True +REMOTE_AUTH_BACKEND = 'netbox.authentication.LDAPBackend' +EOF +else + cat << EOF +# Remote authentication support +REMOTE_AUTH_ENABLED = False +REMOTE_AUTH_BACKEND = 'netbox.authentication.RemoteUserBackend' +EOF +fi + +cat << EOF +REMOTE_AUTH_HEADER = 'HTTP_REMOTE_USER' +REMOTE_AUTH_AUTO_CREATE_USER = True +REMOTE_AUTH_DEFAULT_GROUPS = [] +REMOTE_AUTH_DEFAULT_PERMISSIONS = {} + +# This determines how often the GitHub API is called to check the latest release of NetBox. Must be at least 1 hour. +RELEASE_CHECK_TIMEOUT = 24 * 3600 + +# This repository is used to check whether there is a new release of NetBox available. Set to None to disable the +# version check or use the URL below to check for release in the official NetBox repository. + +EOF + +if [ "$UPDATE_CHECK" != "" ]; then + cat << EOF +RELEASE_CHECK_URL = 'https://api.github.com/repos/netbox-community/netbox/releases' + +EOF +else + cat << EOF +RELEASE_CHECK_URL = None + +EOF +fi + +if [ "$REPORTS_ROOT" != "" ]; then + cat << EOF +# The file path where custom reports will be stored. A trailing slash is not needed. Note that the default value of +# this setting is derived from the installed location. +REPORTS_ROOT = '$REPORTS_ROOT' + +EOF +fi + +if [ "$SCRIPTS_ROOT" != "" ]; then + cat << EOF +# The file path where custom scripts will be stored. A trailing slash is not needed. Note that the default value of +# this setting is derived from the installed location. +SCRIPTS_ROOT = '$SCRIPTS_ROOT' + +EOF +fi + +cat << EOF +# By default, NetBox will store session data in the database. Alternatively, a file path can be specified here to use +# local file storage instead. (This can be useful for enabling authentication on a standby instance with read-only +# database access.) Note that the user as which NetBox runs must have read and write permissions to this path. +SESSION_FILE_PATH = None + +# Time zone (default: UTC) +TIME_ZONE = 'UTC' + +# Date/time formatting. See the following link for supported formats: +# https://docs.djangoproject.com/en/stable/ref/templates/builtins/#date +DATE_FORMAT = 'N j, Y' +SHORT_DATE_FORMAT = 'Y-m-d' +TIME_FORMAT = 'g:i a' +SHORT_TIME_FORMAT = 'H:i:s' +DATETIME_FORMAT = 'N j, Y g:i a' +SHORT_DATETIME_FORMAT = 'Y-m-d H:i' +EOF diff --git a/type/__netbox/files/ldap_config.py.sh b/type/__netbox/files/ldap_config.py.sh new file mode 100755 index 0000000..4e6b099 --- /dev/null +++ b/type/__netbox/files/ldap_config.py.sh @@ -0,0 +1,82 @@ +#!/bin/sh + +# no configuration if there are no ldap parameters +if [ -z "$USE_LDAP" ]; then + # skip + cat << EOF +############################## +# LDAP-backed authentication # +############################## + +# no options set +EOF + exit 0 +fi + + +cat << EOF +############################## +# LDAP-backed authentication # +############################## + +import ldap +from django_auth_ldap.config import LDAPSearch, PosixGroupType + +# Server URI +AUTH_LDAP_SERVER_URI = "$LDAP_SERVER" + +# Set the DN and password for the NetBox service account. +AUTH_LDAP_BIND_DN = "$LDAP_BIND_DN" +AUTH_LDAP_BIND_PASSWORD = "$LDAP_BIND_PASSWORD" + +# Search for user entry. +AUTH_LDAP_USER_SEARCH = LDAPSearch("$LDAP_USER_BASE", + ldap.SCOPE_SUBTREE, + "(uid=%(user)s)") + +# You can map user attributes to Django attributes as so. +AUTH_LDAP_USER_ATTR_MAP = { + "first_name": "givenName", + "last_name": "sn", + "email": "mail" +} +EOF + +if [ "$LDAP_GROUP_BASE" != "" ]; then + cat << EOF + +# This search ought to return all groups to which the user belongs. django_auth_ldap uses this to determine group +# hierarchy. +AUTH_LDAP_GROUP_SEARCH = LDAPSearch("$LDAP_GROUP_BASE", ldap.SCOPE_SUBTREE, + "(objectClass=posixGroup)") +AUTH_LDAP_GROUP_TYPE = PosixGroupType() + +# Mirror LDAP group assignments. +AUTH_LDAP_MIRROR_GROUPS = True +# For more granular permissions, map LDAP groups to Django groups. +AUTH_LDAP_FIND_GROUP_PERMS = True +EOF + + if [ "$LDAP_REQUIRE_GROUP" != "" ]; then + cat << EOF + +# Define a group required to login. +AUTH_LDAP_REQUIRE_GROUP = "$LDAP_REQUIRE_GROUP" +EOF + fi + + cat << EOF + +# Define special user types using groups. Exercise great caution when assigning superuser status. +AUTH_LDAP_USER_FLAGS_BY_GROUP = { +EOF + # superuser + if [ "$LDAP_SUPERUSER_GROUP" != "" ]; then + echo " \"is_superuser\": \"$LDAP_SUPERUSER_GROUP\"," + fi + # staff user + if [ "$LDAP_STAFF_GROUP" != "" ]; then + echo " \"is_staff\": \"$LDAP_STAFF_GROUP\"," + fi + echo "}" +fi diff --git a/type/__netbox/files/netbox-rq.service b/type/__netbox/files/netbox-rq.service new file mode 100644 index 0000000..330e675 --- /dev/null +++ b/type/__netbox/files/netbox-rq.service @@ -0,0 +1,24 @@ +[Unit] +Description=NetBox Request Queue Worker +Documentation=https://netbox.readthedocs.io/en/stable/ +PartOf=netbox.service +Wants=network.target +After=netbox.service +After=network.target +After=redis-server.service postgresql.service + +[Service] +Type=simple + +User=netbox +Group=netbox +WorkingDirectory=/opt/netbox + +ExecStart=/opt/netbox/venv/bin/python3 /opt/netbox/netbox/manage.py rqworker + +Restart=on-failure +RestartSec=30 +PrivateTmp=true + +[Install] +WantedBy=multi-user.target diff --git a/type/__netbox/files/netbox.service b/type/__netbox/files/netbox.service new file mode 100644 index 0000000..68010e9 --- /dev/null +++ b/type/__netbox/files/netbox.service @@ -0,0 +1,13 @@ +[Unit] +Description=NetBox Service Wrapper +Documentation=https://netbox.readthedocs.io/en/stable/ +Wants=network.target +After=network.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/bin/true + +[Install] +WantedBy=multi-user.target diff --git a/type/__netbox/files/netbox.socket.sh b/type/__netbox/files/netbox.socket.sh new file mode 100755 index 0000000..2ef9e81 --- /dev/null +++ b/type/__netbox/files/netbox.socket.sh @@ -0,0 +1,33 @@ +#!/bin/sh -e +# __netbox/files/netbox.socket.sh + +# This is shared between all WSGI-server types. + +# Arguments: +# 1: File which list all sockets to listen on (sepearated by \n) + +if [ $# -ne 1 ]; then + printf "netbox.socket.sh: argument \$1 missing or too much given!\n" >&2 + exit 1 +fi + + +cat << UNIT +[Unit] +Description=Socket for NetBox via $TYPE + +[Socket] +UNIT + +# read all sockets to listen to +while read -r line; do + printf "ListenStream=%s\n" "$line" +done < "$1" + +cat << UNIT +SocketUser=netbox +SocketGroup=www-data + +[Install] +WantedBy=sockets.target +UNIT diff --git a/type/__netbox/gencode-remote b/type/__netbox/gencode-remote new file mode 100755 index 0000000..5d4b7be --- /dev/null +++ b/type/__netbox/gencode-remote @@ -0,0 +1,120 @@ +#!/bin/sh -e + +old_version="$(cat "$__object/explorer/version")" +VERSION=$(cat "$__object/parameter/version") + +src="netbox-$VERSION" +archive="v$VERSION.tar.gz" +url="https://github.com/netbox-community/netbox/archive/$archive" +install_dir=/opt/netbox/netbox + +if [ "$VERSION" != "$old_version" ]; then + cat << EOF +# Ensure that coreutils is installed. +if [ ! -x \$(which mktemp) ]; then + echo "mktemp is not available on the remote host." >&2 + exit 1 +fi + +# Create temporary working directory. +tmpdir=\$(mktemp -d) +cd "\$tmpdir" + +# Download and extract sources. +curl -sS -L '$url' > '$archive' +tar xf '$archive' + + +# virtualenv is given already by __pyvenv, just using it + +# backup requirement files +if [ -f /opt/netbox/requirements.txt ]; then + mv /opt/netbox/requirements.txt /opt/netbox/old-requirements.txt +else + # preseve file-not-found errors and warnings + touch /opt/netbox/old-requirements.txt +fi +cp '$src/requirements.txt' /opt/netbox/ + +# Uninstall packages not required anymore +# if versions not be shortend, they will be ignored by pip, but not by comm +# all of this could be done with grep, too, but it's still must be shortend with awk +awk -F== '{print \$1}' '/opt/netbox/requirements.txt' | sort > "\$tmpdir/curr-reqs.txt" +awk -F== '{print \$1}' '/opt/netbox/old-requirements.txt' | sort > "\$tmpdir/old-reqs.txt" +comm -23 "\$tmpdir/old-reqs.txt" "\$tmpdir/curr-reqs.txt" > "\$tmpdir/pip-uninstall.txt" + +# only uninstall if something is available (to avoid errors cause of this) +if [ -s "\$tmpdir/pip-uninstall.txt" ]; then + /opt/netbox/venv/bin/pip3 uninstall -qy -r "\$tmpdir/pip-uninstall.txt" +fi + +# Install python dependencies. +# avoid gunicorn, because it will be done in an other type +grep -v "^gunicorn==" "\$tmpdir/$src/requirements.txt" \ + | xargs /opt/netbox/venv/bin/pip3 install -q +EOF + + if [ -f "$__object/parameter/ldap-server" ]; then + echo "/opt/netbox/venv/bin/pip3 install -q django-auth-ldap" + else + echo "/opt/netbox/venv/bin/pip3 uninstall -qy django-auth-ldap" + fi + + cat << EOF + +# Deploy sources and restore configuration. +rm -rf '$install_dir' +cp -r '$src/netbox' '$install_dir' +# force links to the cdist directory +ln -fs /opt/netbox/cdist/configuration.py '$install_dir/netbox/configuration.py' +ln -fs /opt/netbox/cdist/ldap_config.py '$install_dir/netbox/ldap_config.py' + +# Set final permissions. +chown -R netbox /opt/netbox + + +# NetBox manage scripts +# Run database migrations. +sudo -u netbox /opt/netbox/venv/bin/python3 /opt/netbox/netbox/manage.py migrate +# Generate static assets. +sudo -u netbox /opt/netbox/venv/bin/python3 /opt/netbox/netbox/manage.py collectstatic --no-input +# Delete any stale content types +sudo -u netbox /opt/netbox/venv/bin/python3 /opt/netbox/netbox/manage.py remove_stale_contenttypes --no-input +# Delete any expired user sessions +sudo -u netbox /opt/netbox/venv/bin/python3 /opt/netbox/netbox/manage.py clearsessions +# Clear all cached data +sudo -u netbox /opt/netbox/venv/bin/python3 /opt/netbox/netbox/manage.py invalidate all + +# Remove temporary working directory. +cd / +rm -rf "\$tmpdir" + +# Save version after successful installation +printf "%s\\n" "$VERSION" > /opt/netbox/cdist/version + +EOF + + # meta + printf "installed %s\n" "$VERSION" >> "$__messages_out" + changes=yes +fi + +# check if configuration changed +if grep -q "^__file/opt/netbox/" "$__messages_in"; then + # meta + printf "configured\n" >> "$__messages_out" + changes=yes +fi + + +# Check for changes +if [ "$changes" = "yes" ]; then + # After the upstream upgrade.sh script, it's ok to migrate while the + # application is running ;) + + # restarting after changes + cat << EOF +# Restart service. All required services are included with netbox.service. +systemctl restart netbox +EOF +fi diff --git a/type/__netbox/man.rst b/type/__netbox/man.rst new file mode 100644 index 0000000..5f78f1d --- /dev/null +++ b/type/__netbox/man.rst @@ -0,0 +1,274 @@ +cdist-type__netbox(7) +===================== + +NAME +---- +cdist-type__netbox - Install and configure NetBox + + +DESCRIPTION +----------- +This (singleton) type installs and configures a NetBox instance, a web +application to help manage and document computer networks. + +It installs it with the user ``netbox`` at ``/opt/netbox`` with `python-venv`. +It setup systemd unit files for the services `netbox` and `netbox-rq`. The +`netbox` service only wrap all netbox related services, e.g. restarting and +so one will be delegated to all related services. + +The application is still not accessable because a WSGI server is required. To +access the application through WSGI, uWSGI or Gunicorn can be used. The setup +can be done via there own types `__netbox_gunicorn` and `__netbox_uwsgi`. + +The Gunicorn setup is recommended from the NetBox documentation. Consult each +manual page to decide. The types must be called after the `__netbox` type. + + +REQUIRED PARAMETERS +------------------- +version + NetBox version to be installed. You can find the correct and newest version + on GitHub at the NetBox project page under + "`Releases `_". + +database + PostgreSQL database name. + +database-user + PostgreSQL database user. + +database-password + PostgreSQL database password. + +host + Hostname (domain or IP address) on which the application is served. + Multiple hostnames are possible; given as multiple arguments. + + +OPTIONAL PARAMETERS +------------------- +secret-key + Random secret key of at least 50 alphanumeric characters and symbols. This + key must be unique to this installation and must not be shared outside the + local system. If no secret key is given, the type generates an own 50 chars + long key and saves it on the remote host to remember it for the next run. + + The secret, random string is used to assist in the creation new + cryptographic hashes for passwords and HTTP cookies. It is not directly + used for hasing user passwords or for encrpted storage. It can be changed + at any time, but will invalidate all existing sessions. + +database-host + PostgreSQL database hostname. Defaults to ``localhost``. + +database-port + PostgreSQL database port. Defaults to empty (uses the default port). + +ldap-server + LDAP server URI. Enables LDAP-backed authentication if specified. + +ldap-bind-dn + DN for the NetBox service account. Required for LDAP authentication. + +ldap-bind-password + Password for the NetBox service account. Required for LDAP authentication. + +ldap-user-base + Base used for searching user entries. Required for LDAP authentication. + +ldap-group-base + Base used for searching group entries. + +ldap-require-group + Group required to login. + +ldap-staff-group + Make members of this group to "staff". This gives the users "Admin Access", + which means access to the "NetBox Administration" site. + +ldap-superuser-group + Make members of this groups superusers. + +redis-host + Redis database hostname. Defaults to ``localhost``. + +redis-port + Redis database port. Defaults to ``6379``. + +redis-password + Redis password. Defaults to empty password. + +redis-dbid-offset + Offset to set the redis database id's. The `tasks` database id is + `offset + 0` and `caching` is `offset + 1`. The offset defaults to ``0``. + +smtp-host + Host of the SMTP email server. Defaults to ``localhost``. + +smtp-port + Port of the SMTP email server. Defaults to ``25``. + +smtp-user + Username to access the SMTP email server. Defaults to empty. + +smtp-password + Password to access the SMTP email server. Defaults to empty. + +smtp-from-email + Email from which NetBox will be sent of. Defaults to empty. + +basepath + Base URL path if accessing netbox within a directory instead of directly the + webroot ``/``. For example, if installed at https://example.com/netbox/, set + the value ``netbox/``. + +https-proxy + Proxy which will be used with any HTTP request like webhooks. + +data-root + This parameter set's the media, reports and scripts root to subdirectories + of the given directory. Values can be overwritten by special parameters like + `--media-root` for example. Use this option if you want to store persistant + data of netbox on an other partition. A trailing slash is not needed. + + The data directories have following predefined sub-directory names: + + media root: + ``$data_root/media`` + reports root: + ``$data_root/reports`` + scripts root: + ``$data_root/scripts`` + + To preserve all data from installation upgrades - which just replace the + installation directory - the data will be kept in the netbox home directory + rather than the installation directory by default (``/opt/netbox/data/``). + This way, no data will be deleted after the installation directory + replacement because it remains outside of the installation directory. + +media-root + The file path to where media files (like image attachments) are stored. + Change this path if you require to store data on an other partiotion. + A trailing slash is not needed. Defaults to ``$data_root/media``. + +reports-root + The file path of where custom reports are kept. Change this path if you + require to store data on an other partition. A trailing slash is not + needed. Defaults to ``$data_root/reports``. + +scripts-root + The file path of where custom scripts are kept. Change this path if you + require to store data on an other partition. A trailing slash is not + needed. Defaults to ``$data_root/scripts``. + + +BOOLEAN PARAMETERS +------------------ +redis-ssl + Enables a secure TLS/SSL connection to the redis database. By default, ssl + is disabled. + +smtp-use-tls + Uses TLS to connect to the SMTP email server. `See documentation + `__ + for more information. + +smtp-use-ssl + Uses implicit TLS with the SMTP email server. `See documentation + `__ + for more information. + +login-required + Sets if a login is required to access all sites. By default, anonymous + users can see most data (excluding secrets) but not make any changes. + +update-notify + Enables the NetBox version check for new upstream updates. It checks every + 24 hours for new releases and notify the admin users in the gui if any. + + +MESSAGES +-------- +installed $VERSION + Netbox was fresh installed or updated. The new version number is appended. + +configured + Some configuration files got updated and therefore the service was + restarted. This message will not be echoed if configuration got updated due + a standard installation. + + +EXAMPLES +-------- + +.. code-block:: sh + + __netbox --version 2.8.7 --database netbox \ + --database-password "secretsecretsecret" \ + --secret-key "secretsecretsecret" \ + --host "${__target_host:?}" \ + --host "cool-netbox.xyz" \ + --ldap-server "ldaps://ldap.domain.tld" \ + --ldap-bind-dn "uid=netbox,ou=services,dc=domain,dc=tld" \ + --ldap-bind-password "secretsecretsecret" \ + --ldap-user-base "ou=users,dc=domain,dc=tld" \ + --ldap-group-base "ou=groups,dc=domain,dc=tld" \ + --ldap-require-group "cn=netbox-login,ou=groups,dc=domain,dc=tld" \ + --ldap-superuser-group "cn=netbox-admin,ou=groups,dc=domain,dc=tld" + # using recommended gunicorn setup + require="__netbox" __netbox_gunicorn + + +NOTES +----- +The configuration of NetBox contains more optional settings than that what can +be set with this type. If you think an important setting is missing or there +is a more good way to inject python code for dynamic configuration variables, +you are welcome to contribute! + +- `Possible optional settings + `_ + +If you not setup ldap authentification, you may be interested into how to +`setting up a super user +`_ +directly on the machine to be able to access and use NetBox. + +You may also be interested of writing a own type which handles the creation of +the super user. To do this non-interactivly, see the ansible role as `reference +`_. + +If you change the secret key while the netbox instance is running, there is a +time frame where the access to the application corrupts the whole database. +Then, you need to restore a backup or wipe the database. + +Currently, the cause is not clear, but it should work if you do not touch +netbox while the configuration is done (do not shut it down, too). It only +applies for changes of the secret key, which not happen normally. + +Maybe the `--restart` flag for the `__systemd_unit` types is not the best idea, +but avoids that the changes will not be applied. It could be solved if the type +would send messages from his actions. + + +SEE ALSO +-------- +`NetBox documentation `_ + +:strong:`cdist-type__netbox_gunicorn`\ (7) +:strong:`cdist-type__netbox_uwsgi`\ (7) + + +AUTHORS +------- +Timothée Floure +Matthias Stecher + + +COPYING +------- +Copyright \(C) 2020 Timothée Floure. +Copyright \(C) 2020 Matthias Stecher. +You can redistribute it and/or modify it under the terms of the GNU +General Public License as published by the Free Software Foundation, +either version 3 of the License, or (at your option) any later version. diff --git a/type/__netbox/manifest b/type/__netbox/manifest new file mode 100755 index 0000000..4be49bd --- /dev/null +++ b/type/__netbox/manifest @@ -0,0 +1,226 @@ +#!/bin/sh -e + +os=$(cat "$__global/explorer/os") + +case "$os" in + debian|ubuntu) + # Install netbox dependencies. + for pkg in python3-pip python3-venv python3-dev build-essential libxml2-dev \ + libxslt1-dev libffi-dev libpq-dev libssl-dev zlib1g-dev curl sudo; do + __package $pkg + done + + if [ -f "$__object/parameter/ldap-server" ]; then + for pkg in libldap2-dev libsasl2-dev libssl-dev; do + __package $pkg + done + fi + ;; + *) + printf "Your operating system (%s) is currently not supported by this type (%s)\n" "$os" "${__type##*/}" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + + +DATABASE_NAME=$(cat "$__object/parameter/database") +export DATABASE_NAME +DATABASE_USER="$(cat "$__object/parameter/database-user")" +export DATABASE_USER +DATABASE_PASSWORD=$(cat "$__object/parameter/database-password") +export DATABASE_PASSWORD +DATABASE_HOST="$(cat "$__object/parameter/database-host")" +export DATABASE_HOST +DATABASE_PORT="$(cat "$__object/parameter/database-port")" +export DATABASE_PORT + +# list of hosts +ALLOWED_HOSTS="" +while read -r hostname; do + # shellcheck disable=SC2089 + ALLOWED_HOSTS="$ALLOWED_HOSTS '$hostname'," +done < "$__object/parameter/host" +# shellcheck disable=SC2090 +export ALLOWED_HOSTS + +if [ -f "$__object/parameter/secret-key" ]; then + SECRET_KEY=$(cat "$__object/parameter/secret-key") +elif [ -s "$__object/explorer/secretkey" ]; then + # take the key that is already used + SECRET_KEY="$(cat "$__object/explorer/secretkey")" +else + # Can be done over netbox/generate_secret_key.py too, but it can't be + # generated right now where it's required (only if it's preloaded for + # this type to execute it now). + # Generates a 50-character long key with the same character set like + # the helper script. Must escape the '-' to be no character range. + SECRET_KEY="$(tr -cd '!@#$%^&*(\-_=+)[:alnum:]' < /dev/urandom | head -c50)" +fi +export SECRET_KEY + +if [ -f "$__object/parameter/ldap-server" ]; then + LDAP_SERVER=$(cat "$__object/parameter/ldap-server") + USE_LDAP=yes + export LDAP_SERVER +fi +if [ -f "$__object/parameter/ldap-bind-dn" ]; then + LDAP_BIND_DN=$(cat "$__object/parameter/ldap-bind-dn") + USE_LDAP=yes + export LDAP_BIND_DN +fi +if [ -f "$__object/parameter/ldap-bind-password" ]; then + LDAP_BIND_PASSWORD=$(cat "$__object/parameter/ldap-bind-password") + USE_LDAP=yes + export LDAP_BIND_PASSWORD +fi +if [ -f "$__object/parameter/ldap-user-base" ]; then + LDAP_USER_BASE=$(cat "$__object/parameter/ldap-user-base") + USE_LDAP=yes + export LDAP_USER_BASE +fi +if [ -f "$__object/parameter/ldap-group-base" ]; then + LDAP_GROUP_BASE=$(cat "$__object/parameter/ldap-group-base") + export LDAP_GROUP_BASE +fi +if [ -f "$__object/parameter/ldap-require-group" ]; then + LDAP_REQUIRE_GROUP=$(cat "$__object/parameter/ldap-require-group") + export LDAP_REQUIRE_GROUP +fi +if [ -f "$__object/parameter/ldap-superuser-group" ]; then + LDAP_SUPERUSER_GROUP=$(cat "$__object/parameter/ldap-superuser-group") + export LDAP_SUPERUSER_GROUP +fi +if [ -f "$__object/parameter/ldap-staff-group" ]; then + LDAP_STAFF_GROUP="$(cat "$__object/parameter/ldap-staff-group")" + export LDAP_STAFF_GROUP +fi +# export if base ldap parameters are used +export USE_LDAP + +# have default values +REDIS_HOST="$(cat "$__object/parameter/redis-host")" +export REDIS_HOST +REDIS_PORT="$(cat "$__object/parameter/redis-port")" +export REDIS_PORT +REDIS_PASSWORD="$(cat "$__object/parameter/redis-password")" +export REDIS_PASSWORD +REDIS_DBID_OFFSET="$(cat "$__object/parameter/redis-dbid-offset")" +export REDIS_DBID_OFFSET +if [ -f "$__object/parameter/redis-ssl" ]; then + REDIS_SSL="True" +else + REDIS_SSL="False" +fi +export REDIS_SSL + +SMTP_HOST="$(cat "$__object/parameter/smtp-host")" +export SMTP_HOST +SMTP_PORT="$(cat "$__object/parameter/smtp-port")" +export SMTP_PORT +SMTP_USER="$(cat "$__object/parameter/smtp-user")" +export SMTP_USER +SMTP_PASSWORD="$(cat "$__object/parameter/smtp-password")" +export SMTP_PASSWORD +SMTP_FROM_EMAIL="$(cat "$__object/parameter/smtp-from-email")" +export SMTP_FROM_EMAIL + +if [ -f "$__object/parameter/smtp-use-ssl" ]; then + SMTP_USE_SSL="True" +else + SMTP_USE_SSL="False" +fi +export SMTP_USE_SSL +if [ -f "$__object/parameter/smtp-use-tls" ]; then + if [ "$SMTP_USE_SSL" = "True" ]; then + echo "options --smtp-use-ssl and --smtp-use-tls are not compatible" >&2 + exit 2 + fi + SMTP_USE_TLS="True" +else + SMTP_USE_TLS="False" +fi +export SMTP_USE_TLS + +BASEPATH="$(cat "$__object/parameter/basepath")" +export BASEPATH + +if [ -f "$__object/parameter/http-proxy" ]; then + HTTP_PROXY=$(cat "$__object/parameter/http-proxy") + export HTTP_PROXY +fi +if [ -f "$__object/parameter/https-proxy" ]; then + HTTPS_PROXY=$(cat "$__object/parameter/https-proxy") + export HTTPS_PROXY +fi + +if [ -f "$__object/parameter/login-required" ]; then + LOGIN_REQUIRED="True" +else + LOGIN_REQUIRED="False" +fi +export LOGIN_REQUIRED + +data_root="$(cat "$__object/parameter/data-root")" +MEDIA_ROOT="$data_root/media" +REPORTS_ROOT="$data_root/reports" +SCRIPTS_ROOT="$data_root/scripts" + +if [ -f "$__object/parameter/media-root" ]; then + MEDIA_ROOT="$(cat "$__object/parameter/media-root")" +fi +export MEDIA_ROOT +if [ -f "$__object/parameter/reports-root" ]; then + REPORTS_ROOT="$(cat "$__object/parameter/reports-root")" +fi +export REPORTS_ROOT +if [ -f "$__object/parameter/scripts-root" ]; then + SCRIPTS_ROOT="$(cat "$__object/parameter/scripts-root")" +fi +export SCRIPTS_ROOT + +if [ -f "$__object/parameter/update-notify" ]; then + UPDATE_CHECK="yes" + export UPDATE_CHECK +fi + + +# Create system user used to run netbox. +__user netbox --system --home /opt/netbox --create-home +# Generate python environment (user will be set by gencode-remote) +require="__user/netbox" __pyvenv /opt/netbox/venv/ + +# Generate and upload netbox configuration. +mkdir -p "$__object/files" +"$__type/files/configuration.py.sh" > "$__object/files/configuration.py" +"$__type/files/ldap_config.py.sh" > "$__object/files/ldap_config.py" + +require="__user/netbox" __directory /opt/netbox/cdist +require="__directory/opt/netbox/cdist" __file \ + /opt/netbox/cdist/configuration.py --mode 640 --owner netbox \ + --source "$__object/files/configuration.py" + +if [ -f "$__object/parameter/ldap-server" ]; then + require="__directory/opt/netbox/cdist" __file \ + /opt/netbox/cdist/ldap_config.py --mode 640 --owner netbox \ + --source "$__object/files/ldap_config.py" +else + require="__directory/opt/netbox/cdist" __file \ + /opt/netbox/cdist/ldap_config.py --state absent +fi + +# save secret +require="__directory/opt/netbox/cdist" __file /opt/netbox/cdist/secretkey \ + --mode 400 --owner netbox --source - << SECRET +$SECRET_KEY +SECRET + + +# Upload systemd unit for worker and wsgi service +# does not restart netbox on change cause it only restart all other services +__systemd_unit netbox.service \ + --source "$__type/files/netbox.service" \ + --enablement-state enabled +__systemd_unit netbox-rq.service \ + --source "$__type/files/netbox-rq.service" \ + --enablement-state enabled --restart diff --git a/type/__netbox/parameter/boolean b/type/__netbox/parameter/boolean new file mode 100644 index 0000000..d568037 --- /dev/null +++ b/type/__netbox/parameter/boolean @@ -0,0 +1,5 @@ +redis-ssl +smtp-use-ssl +smtp-use-tls +login-required +update-notify diff --git a/type/__netbox/parameter/default/basepath b/type/__netbox/parameter/default/basepath new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/type/__netbox/parameter/default/basepath @@ -0,0 +1 @@ + diff --git a/type/__netbox/parameter/default/data-root b/type/__netbox/parameter/default/data-root new file mode 100644 index 0000000..45faab0 --- /dev/null +++ b/type/__netbox/parameter/default/data-root @@ -0,0 +1 @@ +/opt/netbox/data diff --git a/type/__netbox/parameter/default/database-host b/type/__netbox/parameter/default/database-host new file mode 100644 index 0000000..2fbb50c --- /dev/null +++ b/type/__netbox/parameter/default/database-host @@ -0,0 +1 @@ +localhost diff --git a/type/__netbox/parameter/default/database-port b/type/__netbox/parameter/default/database-port new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/type/__netbox/parameter/default/database-port @@ -0,0 +1 @@ + diff --git a/type/__netbox/parameter/default/redis-dbid-offset b/type/__netbox/parameter/default/redis-dbid-offset new file mode 100644 index 0000000..573541a --- /dev/null +++ b/type/__netbox/parameter/default/redis-dbid-offset @@ -0,0 +1 @@ +0 diff --git a/type/__netbox/parameter/default/redis-host b/type/__netbox/parameter/default/redis-host new file mode 100644 index 0000000..2fbb50c --- /dev/null +++ b/type/__netbox/parameter/default/redis-host @@ -0,0 +1 @@ +localhost diff --git a/type/__netbox/parameter/default/redis-password b/type/__netbox/parameter/default/redis-password new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/type/__netbox/parameter/default/redis-password @@ -0,0 +1 @@ + diff --git a/type/__netbox/parameter/default/redis-port b/type/__netbox/parameter/default/redis-port new file mode 100644 index 0000000..a8c4b8e --- /dev/null +++ b/type/__netbox/parameter/default/redis-port @@ -0,0 +1 @@ +6379 diff --git a/type/__netbox/parameter/default/smtp-from-email b/type/__netbox/parameter/default/smtp-from-email new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/type/__netbox/parameter/default/smtp-from-email @@ -0,0 +1 @@ + diff --git a/type/__netbox/parameter/default/smtp-host b/type/__netbox/parameter/default/smtp-host new file mode 100644 index 0000000..2fbb50c --- /dev/null +++ b/type/__netbox/parameter/default/smtp-host @@ -0,0 +1 @@ +localhost diff --git a/type/__netbox/parameter/default/smtp-password b/type/__netbox/parameter/default/smtp-password new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/type/__netbox/parameter/default/smtp-password @@ -0,0 +1 @@ + diff --git a/type/__netbox/parameter/default/smtp-port b/type/__netbox/parameter/default/smtp-port new file mode 100644 index 0000000..7273c0f --- /dev/null +++ b/type/__netbox/parameter/default/smtp-port @@ -0,0 +1 @@ +25 diff --git a/type/__netbox/parameter/default/smtp-user b/type/__netbox/parameter/default/smtp-user new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/type/__netbox/parameter/default/smtp-user @@ -0,0 +1 @@ + diff --git a/type/__netbox/parameter/optional b/type/__netbox/parameter/optional new file mode 100644 index 0000000..9495f7a --- /dev/null +++ b/type/__netbox/parameter/optional @@ -0,0 +1,27 @@ +secret-key +database-host +database-port +ldap-server +ldap-bind-dn +ldap-bind-password +ldap-user-base +ldap-group-base +ldap-require-group +ldap-staff-group +ldap-superuser-group +redis-host +redis-port +redis-password +redis-dbid-offset +smtp-host +smtp-port +smtp-user +smtp-password +smtp-from-email +basepath +http-proxy +https-proxy +data-root +media-root +reports-root +scripts-root diff --git a/type/__netbox/parameter/required b/type/__netbox/parameter/required new file mode 100644 index 0000000..02fca9f --- /dev/null +++ b/type/__netbox/parameter/required @@ -0,0 +1,4 @@ +version +database +database-user +database-password diff --git a/type/__netbox/parameter/required_multiple b/type/__netbox/parameter/required_multiple new file mode 100644 index 0000000..c70dc2d --- /dev/null +++ b/type/__netbox/parameter/required_multiple @@ -0,0 +1 @@ +host diff --git a/type/__netbox/singleton b/type/__netbox/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__netbox_gunicorn/explorer/installed b/type/__netbox_gunicorn/explorer/installed new file mode 100755 index 0000000..c6f5d87 --- /dev/null +++ b/type/__netbox_gunicorn/explorer/installed @@ -0,0 +1,4 @@ +#!/bin/sh -e + +# print version if available +/opt/netbox/venv/bin/pip3 show gunicorn | awk '/Version:/{print $2}' diff --git a/type/__netbox_gunicorn/explorer/should_installed b/type/__netbox_gunicorn/explorer/should_installed new file mode 100755 index 0000000..073be92 --- /dev/null +++ b/type/__netbox_gunicorn/explorer/should_installed @@ -0,0 +1,3 @@ +#!/bin/sh -e + +awk -v FS="==" '$1 ~ /gunicorn/{print $2}' /opt/netbox/requirements.txt diff --git a/type/__netbox_gunicorn/files/gunicorn.py.sh b/type/__netbox_gunicorn/files/gunicorn.py.sh new file mode 100755 index 0000000..c1e6ee5 --- /dev/null +++ b/type/__netbox_gunicorn/files/gunicorn.py.sh @@ -0,0 +1,31 @@ +#!/bin/sh -e + +# Generates gunicorn config +# see https://docs.gunicorn.org/en/stable/settings.html + +# fix missing $__explorer +# see https://code.ungleich.ch/ungleich-public/cdist/-/issues/834 +__explorer="$__global/explorer" + +# size workes by cpu +cores="$(cat "$__explorer/cpu_cores")" + + +cat << EOF +# The IP address (typically localhost) and port that the Netbox WSGI process should listen on +#bind = done via systemd socket 'gunicorn-netbox.socket' + +# Number of gunicorn workers to spawn. This should typically be 2n+1, where +# n is the number of CPU cores present. +workers = $(( 2*cores + 1 )) + +# Number of threads per worker process +threads = 3 + +# Timeout (in seconds) for a request to complete +timeout = 120 + +# The maximum number of requests a worker can handle before being respawned +max_requests = 5000 +max_requests_jitter = 500 +EOF diff --git a/type/__netbox_gunicorn/files/netbox.service b/type/__netbox_gunicorn/files/netbox.service new file mode 100644 index 0000000..28b6b45 --- /dev/null +++ b/type/__netbox_gunicorn/files/netbox.service @@ -0,0 +1,29 @@ +[Unit] +Description=NetBox Gunicorn WSGI Service +Documentation=https://netbox.readthedocs.io/en/stable/ +PartOf=netbox.service +Requires=netbox-rq.service +Requires=gunicorn-netbox.socket +Wants=network.target +After=netbox.service +After=network.target +After=redis-server.service postgresql.service + +[Service] +Type=notify + +User=netbox +Group=netbox +WorkingDirectory=/opt/netbox + +ExecStart=/opt/netbox/venv/bin/gunicorn --pythonpath /opt/netbox/netbox --config /opt/netbox/gunicorn.py netbox.wsgi +# signals: https://docs.gunicorn.org/en/stable/signals.html +ExecReload=kill -HUP $MAINPID +ExecStop=kill -TERM $MAINPID +KillSignal=SIGQUIT + +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=netbox.service diff --git a/type/__netbox_gunicorn/files/netbox.socket.sh b/type/__netbox_gunicorn/files/netbox.socket.sh new file mode 120000 index 0000000..28ce920 --- /dev/null +++ b/type/__netbox_gunicorn/files/netbox.socket.sh @@ -0,0 +1 @@ +../../__netbox/files/netbox.socket.sh \ No newline at end of file diff --git a/type/__netbox_gunicorn/gencode-remote b/type/__netbox_gunicorn/gencode-remote new file mode 100755 index 0000000..4fae788 --- /dev/null +++ b/type/__netbox_gunicorn/gencode-remote @@ -0,0 +1,50 @@ +#!/bin/sh -e + +# control state +state="$(cat "$__object/parameter/state")" + +case "$state" in + # install gunicorn + enabled|disabled) + curr_installed="$(cat "$__object/explorer/installed")" + should_installed="$(cat "$__object/explorer/should_installed")" + + # gunicorn version change + if [ "$curr_installed" != "$should_installed" ]; then + # (re)installing gunicorn + echo "/opt/netbox/venv/bin/pip3 install 'gunicorn==$should_installed'" + + if [ "$curr_installed" != "" ]; then + printf "updated %s to %s\n" "$curr_installed" "$should_installed" \ + >> "$__messages_out" + else + printf "installed\n" >> "$__messages_out" + fi + do_restart=yes + fi + + # configuration changes + if grep -q "^__file/opt/netbox/gunicorn.py:" "$__messages_in"; then + do_restart=yes + printf "configured\n" >> "$__messages_out" + fi + + + # restart gunicorn + if [ "$do_restart" ] && [ "$state" != "disabled" ]; then + cat << EOF +# Restart service +systemctl restart gunicorn-netbox +EOF + fi + ;; + + # uninstall + absent) + # check if installed + if [ -s "$__object/explorer/installed" ]; then + # service already disabled + echo "/opt/netbox/venv/bin/pip3 uninstall -y gunicorn" + printf "uninstalled\n" >> "$__messages_out" + fi +esac diff --git a/type/__netbox_gunicorn/man.rst b/type/__netbox_gunicorn/man.rst new file mode 100644 index 0000000..8860294 --- /dev/null +++ b/type/__netbox_gunicorn/man.rst @@ -0,0 +1,117 @@ +cdist-type__netbox_gunicorn(7) +============================== + +NAME +---- +cdist-type__netbox_gunicorn - Run NetBox with Gunicorn + + +DESCRIPTION +----------- +This (singleton) type installs Gunicorn into the NetBox `python-venv` to host +the NetBox WSGI application. It provides the application as HTTP over the given +sockets. Static content must be served independent of Gunicorn. The Gunicorn +daemon is available as the `gunicorn-netbox` systemd service, but also +available via the `netbox` wrapper service. + +It will use systemd socket activation to listen to the given sockets. This +should allow to bind to privileaged ports (all below 1024) and hot reloads. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +state + Represents the state of the Gunciron application. Defaults to ``enabled``. + + enabled + The Gunicorn service is enabled and running. + disabled + The Gunicorn service is installed, but disabled. + absent + The uWSGI service is not installed and all configuration removed. + + This type does not guarantee anything about the running state of the + service. To be sure about the service is stopped or not, use the type + :strong:`cdist-type__systemd_service`\ (7) after this execution. + +bind-to + The hosts the gunicorn socket should be bind to. Formats are `IP`, + `IP:PORT`, `PATH` or anything other that systemd socket units will + understand as stream. Parameter can be set multiple times. Defaults + to ``127.0.0.1:8001``. + + +BOOLEAN PARAMETERS +------------------ +None. + + +MESSAGES +-------- +installed + The software was installed. + +upgraded $old to $new + The version of the gunicorn software was updated from `$old` to `$new`. + +configured + Configuration for gunicorn changed. + +uninstalled + The Gunicorn application was removed. + +In all cases where the application is still present, it restarts the service to +use the up-to-date version. + + +EXAMPLES +-------- + +.. code-block:: sh + + # simple + __netbox $args + require="__netbox" __netbox_gunicorn + + # with arguments + __netbox $args + require="__netbox" __netbox_gunicorn \ + --bind-to 0.0.0.0:8001 \ + --bind-to 1.2.3.4:5678 + + # replace uwsgi with gunicorn + __netbox $args + require="__netbox" __netbox_uwsgi --state absent + # it should depend on __netbox_uwsgi if they use the same socket + require="__netbox_uwsgi" __netbox_gunicorn --state enabled + + # be sure the service is disabled + __netbox $args + require="__netbox" __netbox_gunicorn --state disabled + require="__netbox_gunicorn" __systemd_service gunicorn-netbox --state stopped + + +SEE ALSO +-------- +`Gunicorn Documentation `_ + +:strong:`cdist-type__netbox`\ (7) +:strong:`cdist-type__netbox_uwsgi`\ (7) + + +AUTHORS +------- +Matthias Stecher + + +COPYING +------- +Copyright \(C) 2020 Matthias Stecher. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__netbox_gunicorn/manifest b/type/__netbox_gunicorn/manifest new file mode 100755 index 0000000..5748e9d --- /dev/null +++ b/type/__netbox_gunicorn/manifest @@ -0,0 +1,57 @@ +#!/bin/sh -e +# __netbox_gunicorn/manifest + +# Check states +state="" +unit_state="" +param_state="$(cat "$__object/parameter/state")" + +case "$param_state" in + enabled|disabled) + state="present" + unit_state="$param_state" + ;; + + absent) + state="absent" + unit_state="disabled" + ;; + + *) + # does not exist + printf "The state '%s' does not exist, can't continue!\n" "$param_state" >&2 + exit 2 + ;; +esac + + +mkdir "$__object/files" + +if [ "$state" = "present" ]; then + # process template + "$__type/files/gunicorn.py.sh" > "$__object/files/gunicorn.py" + + # gunicorn config file + __file /opt/netbox/gunicorn.py \ + --mode 644 --owner netbox \ + --source "$__object/files/gunicorn.py" + +else + # absent config file + __file /opt/netbox/gunicorn.py --state absent +fi + + +TYPE="Gunicorn" +export TYPE + +"$__type/files/netbox.socket.sh" "$__object/parameter/bind-to" \ + > "$__object/files/netbox.socket" + +# install systemd files +__systemd_unit gunicorn-netbox.socket \ + --state "$state" --enablement-state "$unit_state" \ + --source "$__object/files/netbox.socket" --restart +__systemd_unit gunicorn-netbox.service \ + --state "$state" --enablement-state "$unit_state" \ + --source "$__type/files/netbox.service" --restart diff --git a/type/__netbox_gunicorn/parameter/default/bind-to b/type/__netbox_gunicorn/parameter/default/bind-to new file mode 100644 index 0000000..f4c980e --- /dev/null +++ b/type/__netbox_gunicorn/parameter/default/bind-to @@ -0,0 +1 @@ +127.0.0.1:8001 diff --git a/type/__netbox_gunicorn/parameter/default/state b/type/__netbox_gunicorn/parameter/default/state new file mode 100644 index 0000000..86981e6 --- /dev/null +++ b/type/__netbox_gunicorn/parameter/default/state @@ -0,0 +1 @@ +enabled diff --git a/type/__netbox_gunicorn/parameter/optional b/type/__netbox_gunicorn/parameter/optional new file mode 100644 index 0000000..ff72b5c --- /dev/null +++ b/type/__netbox_gunicorn/parameter/optional @@ -0,0 +1 @@ +state diff --git a/type/__netbox_gunicorn/parameter/optional_multiple b/type/__netbox_gunicorn/parameter/optional_multiple new file mode 100644 index 0000000..331c077 --- /dev/null +++ b/type/__netbox_gunicorn/parameter/optional_multiple @@ -0,0 +1 @@ +bind-to diff --git a/type/__netbox_gunicorn/singleton b/type/__netbox_gunicorn/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__netbox_uwsgi/explorer/bind-capability b/type/__netbox_uwsgi/explorer/bind-capability new file mode 100755 index 0000000..c5c0365 --- /dev/null +++ b/type/__netbox_uwsgi/explorer/bind-capability @@ -0,0 +1,12 @@ +#!/bin/sh -e +# explorer/bind-capablility + +# Checks if the uWSGI binary have the capability to bind to privileaged ports +# as a non-root user. It's required if no systemd sockets are used (cause of +# the use of multiple protocols etc.) + +binary="/opt/netbox/venv/bin/uwsgi" +# -v verifies if capability is set +if setcap -q -v CAP_NET_BIND_SERVICE+ep "$binary"; then + echo set +fi diff --git a/type/__netbox_uwsgi/explorer/installed b/type/__netbox_uwsgi/explorer/installed new file mode 100755 index 0000000..a2393d0 --- /dev/null +++ b/type/__netbox_uwsgi/explorer/installed @@ -0,0 +1,4 @@ +#!/bin/sh -e + +# print version if available +/opt/netbox/venv/bin/pip3 show uwsgi | awk '/Version:/{print $2}' diff --git a/type/__netbox_uwsgi/explorer/upgradeable b/type/__netbox_uwsgi/explorer/upgradeable new file mode 100755 index 0000000..f4b0a22 --- /dev/null +++ b/type/__netbox_uwsgi/explorer/upgradeable @@ -0,0 +1,4 @@ +#!/bin/sh -e + +# print latest version if availble +/opt/netbox/venv/bin/pip3 list --outdated | awk '$1 == "uwsgi" {print $3}' diff --git a/type/__netbox_uwsgi/files/netbox.service.sh b/type/__netbox_uwsgi/files/netbox.service.sh new file mode 100755 index 0000000..3705769 --- /dev/null +++ b/type/__netbox_uwsgi/files/netbox.service.sh @@ -0,0 +1,40 @@ +#!/bin/sh -e + +cat << EOF +[Unit] +Description=Netbox uWSGI WSGI Service +Documentation=https://netbox.readthedocs.io/en/stable/ +PartOf=netbox.service +Requires=netbox-rq.service +EOF + +# Add dependency to own socket +if [ "$(cat "$__object/files/systemd_socket")" = "yes" ]; then + echo "Requires=uwsgi-netbox.socket" +fi + +cat << EOF +Wants=network.target +After=netbox.service +After=network.target +After=redis-server.service postgresql.service + +[Service] +Type=notify + +User=netbox +Group=netbox +WorkingDirectory=/opt/netbox + +ExecStart=/opt/netbox/venv/bin/uwsgi --master --chdir /opt/netbox/netbox --module netbox.wsgi uwsgi.ini +# signals: https://uwsgi-docs.readthedocs.io/en/latest/Management.html#signals-for-controlling-uwsgi +ExecReload=kill -HUP \$MAINPID +ExecStop=kill -INT \$MAINPID +KillSignal=SIGQUIT + +Restart=on-failure +RestartSec=30 + +[Install] +WantedBy=netbox.service +EOF diff --git a/type/__netbox_uwsgi/files/netbox.socket.sh b/type/__netbox_uwsgi/files/netbox.socket.sh new file mode 120000 index 0000000..28ce920 --- /dev/null +++ b/type/__netbox_uwsgi/files/netbox.socket.sh @@ -0,0 +1 @@ +../../__netbox/files/netbox.socket.sh \ No newline at end of file diff --git a/type/__netbox_uwsgi/files/uwsgi.ini.sh b/type/__netbox_uwsgi/files/uwsgi.ini.sh new file mode 100755 index 0000000..4bae613 --- /dev/null +++ b/type/__netbox_uwsgi/files/uwsgi.ini.sh @@ -0,0 +1,60 @@ +#!/bin/sh -e + +# Generates uwsgi config +# see https://uwsgi-docs.readthedocs.io/en/latest/Options.html +# or https://uwsgi-docs-additions.readthedocs.io/en/latest/Options.html + +# params: +# 1: parameter name +# 2: parameter value file +# +# output: the lines for the configuration option +multi_options() { + while read -r line; do + printf "%s = %s\n" "$1" "$line" + done < "$2" +} + +# fix missing $__explorer +# see https://code.ungleich.ch/ungleich-public/cdist/-/issues/834 +__explorer="$__global/explorer" + +# size workes by cpu +cores="$(cat "$__explorer/cpu_cores")" + + +cat << EOF +[uwsgi] +; socket(s) to bind +EOF + +if [ "$SYSTEMD_SOCKET" != "yes" ]; then + # special protocol to bind + find "$__object/parameter/" -maxdepth 1 -name "*-bind" -print \ + | while read -r param; do + multi_options "$(basename "$param" | awk -F'-' '{print $1}')-socket" "$param" + done +else + # else, systemd will offer socket + echo "; sockets managed via 'uwsgi-netbox.socket'" + printf "protocol = %s\n" "$PROTOCOL" +fi + + +# multi-process settings +cat << EOF + +; processes and threads +processes = $(( 2*cores + 1 )) +threads = 2 +EOF + + +# optional mapping of static content +if [ "$STATIC_MAP" != "" ]; then + cat << EOF + +; map static content +static-map = /static=/opt/netbox/netbox/static +EOF +fi diff --git a/type/__netbox_uwsgi/gencode-remote b/type/__netbox_uwsgi/gencode-remote new file mode 100755 index 0000000..7c3b826 --- /dev/null +++ b/type/__netbox_uwsgi/gencode-remote @@ -0,0 +1,101 @@ +#!/bin/sh -e + +# control state +state="$(cat "$__object/parameter/state")" + +# Set capabilities to aquire privileaged ports as netbox user. Two modes are +# available to efficiently set capabilites. Assumes libcap-bin is installed as +# default on debian systems. +# +# Arguments: +# 1: mode to detect if capabilites are required to set ('set' or 'correct') +set_bind_cap() { + cap_mode="" # reset variable from the execution before + + # check if capabilites are required after given mode + case "$1" in + # assumes capabilites are not set (cause of new binaries) + set) + if [ "$SYSTEMD_SOCKET" != "yes" ]; then + cap_mode="+ep" + fi + ;; + + # check if capabilities have changed + correct) + if [ -s "$__object/explorer/bind-capability" ]; then + # capabilites are set + if [ "$SYSTEMD_SOCKET" = "yes" ]; then + cap_mode="-ep" # unset + fi + else + # capabilities are unset + if [ "$SYSTEMD_SOCKET" != "yes" ]; then + cap_mode="+ep" # set + fi + fi + ;; + + # faulty mode + *) + echo "called set_bind_cap incorrect (\$1 missing)" >&2 + ;; + esac + + # set capabilities if any + if [ "$cap_mode" ]; then + printf "setcap -q CAP_NET_BIND_SERVICE%s /opt/netbox/venv/bin/uwsgi\n" "$cap_mode" + fi +} +SYSTEMD_SOCKET="$(cat "$__object/files/systemd_socket")" + + +case "$state" in + # install uwsgi + enabled|disabled) + # not installed + if ! [ -s "$__object/explorer/installed" ]; then + echo "/opt/netbox/venv/bin/pip3 install -q uwsgi" + set_bind_cap set + do_restart=yes + printf "installed\n" >> "$__messages_out" + + # updates available + elif [ -s "$__object/explorer/upgradeable" ]; then + echo "/opt/netbox/venv/bin/pip3 install -q --upgrade uwsgi" + set_bind_cap set + do_restart=yes + printf "upgraded\n" >> "$__messages_out" + fi + + # changed configuration + if grep -q "^__file/opt/netbox/uwsgi.ini:" "$__messages_in"; then + do_restart=yes + printf "configured\n" >> "$__messages_out" + fi + + # if no capabilities were set yet, check if any are required + if [ -z "$cap_mode" ]; then + set_bind_cap correct + fi + + + # restart uwsgi + if [ "$do_restart" ] && [ "$state" != "disabled" ]; then + cat << EOF +# Restart service +systemctl restart uwsgi-netbox +EOF + fi + ;; + + # uninstall + absent) + # check if installed + if [ -s "$__object/explorer/installed" ]; then + # service already disabled + echo "/opt/netbox/venv/bin/pip3 uninstall -qy uwsgi" + printf "uninstalled\n" >> "$__messages_out" + fi + ;; +esac diff --git a/type/__netbox_uwsgi/man.rst b/type/__netbox_uwsgi/man.rst new file mode 100644 index 0000000..13dc6dc --- /dev/null +++ b/type/__netbox_uwsgi/man.rst @@ -0,0 +1,183 @@ +cdist-type__netbox_uwsgi(7) +=========================== + +NAME +---- +cdist-type__netbox_uwsgi - Run NetBox with uWSGI + + +DESCRIPTION +----------- +This (singleton) type installs uWSGI into the NetBox `python-venv`. It hosts +the NetBox WSGI application via the WSGI protocol. A further server must be +installed to provide it as HTTP and serve static content. It supports multiple +protocols like uwsgi, fastcgi or HTTP to comunicate with the proxy server. This +application is available via the `uwsgi-netbox` systemd service. It is +controllable via the `netbox` wrapper service, too. + +**As uWSGI will be started as netbox user, it does not have privileges to +bind to a privileaged port (all ports below 1024).** Because uWSGI will +drop privileages anyway before binding to a port, solutions are to use +the systemd sockets to activate the ports as root or set linux kernel +capabilites to bind to such a privileaged port. + +As systemd sockets (or uwsgi itself) do not allow to distinguish multiple +sockets if different protocols are used for different sockets, this type does +not use systemd sockets if it is requested from the user. Using the +``--bind-to`` and ``--protocol`` parameters, it uses the systemd socket +activation. Else, it set the different sockets and protocols natively to uwsgi +and add kernel capabilities to be able to listen to privileaged ports. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +state + Represents the state of the uWSGI application. Defaults to ``enabled``. + + enabled + The uWSGI service is enabled and running. + disabled + The uWSGI service is installed, but disabled. + absent + The uWSGI service is not installed and all configuration removed. + + This type does not guarantee anything about the running state of the + service. To be sure about the service is stopped or not, use the type + :strong:`cdist-type__systemd_service`\ (7) after this execution. + + +bind-to + The socket uwsgi should bind to. Must be UNIX/TCP (or anything that + systemd sockets accept as stream). Defaults to ``127.0.0.1:3031``. Can be + set multiple times. The used protocol is defined by ``--protocol``. + + **By setting up the socket via this parameter, it uses systemd sockets to + handle these.** This parameter will be ignored if a more detailed paramter + is given (``--$proto-bind``). + +protocol + The protocol which should be used for the socket given by the ``--bind-to`` + parameter. Possible values are ``uwsgi``, ``http``, ``fastcgi`` and + ``scgi``. If nothing given, it defaults to ``uwsgi``. + +scgi-bind, uwsgi-bind, http-bind, fastcgi-bind + Bind the application to a specific protocol instead of implicit uwsgi via + ``--bind-to``. If such parameter given, ``--bind-to`` will be ignored. Must + be a UNIX/TCP socket. Can be set multiple times. + + **By using such parameters instead of ``--bind-to``, no systemd sockets + will be used because it can not handle sockets for multiple protocols.** + Instead, the native socket binding will be used. It will add kernel + capabilites to bind to privileaged ports, too. This allow binds to ports + like 80 as netbox user. + + +BOOLEAN PARAMETERS +------------------ +serve-static + Setup uWSGI to serve the static content, too. This is generally not + recommended for real production setups, as it is the job of the reverse + proxy server, who will thread it as static cachable content. This option + is only recommended for small setups or direct usage of the uWSGI socket + like using it as standalone HTTP server for NetBox. + + **Hint**: This parameter does not work in junction with the `__netbox` + parameter ``--basepath``. It is because this type does not know the + parameter value and this case is very unlikly to happen; although an + implementation is not difficult. + + +MESSAGES +-------- +installed + The uwsgi service was installed. + +upgraded + The uwsgi service was upgraded. + +configured + The uwsgi configuration got updated. + +uninstalled + The uWSGI application was removed. + +In all cases where the application is still present, it restarts the service to +use the up-to-date version. + + +EXAMPLES +-------- + +.. code-block:: sh + + # simple + __netbox $args + require="__netbox" __netbox_uwsgi + + # with multiple binds + __netbox $args + require="__netbox" __netbox_uwsgi --bind-to 0.0.0.0:3032 \ + --bind-to 0.0.0.0:3033 + + # with multiple protocols + # parameter `--bind-to` will be ignored + # avoids systemd sockets, but can handle multiple protocols + __netbox $args + require="__netbox" __netbox_uwsgi --uwsgi-bind 0.0.0.0:3031 \ + --http-bind 0.0.0.0:8080 \ + --fastcgi-bind 1.2.3.4:5678 + + # as standalone server + __netbox $args + require="__netbox" __netbox_uwsgi --serve-static --http-bind 0.0.0.0:80 + + # replace gunicorn with uwsgi + __netbox $args + require="__netbox" __netbox_gunicorn --state absent + # it should depend on __netbox_gunicorn if they use the same socket + require="__netbox_gunicorn" __netbox_uwsgi --state enabled + + # be sure the service is disabled + __netbox $args + require="__netbox" __netbox_uwsgi --state disabled + require="__netbox_uwsgi" __systemd_service uwsgi-netbox --state stopped + + +NOTES +----- +If systemd sockets are used, uwsgi can not be reloaded because it does not +handle the socket correctly. It works by completly restarting uwsgi (because +it is near the same cause of the systemd socket) or tweaking the service unit +with the line ``StandardInput=socket``, which limits you to only one address +to bind to (else, the service will not start). + +Maybe someone is interested in enabling log files, because the "log to stdout" +is not the fanciest approach (because it is shown in the journal). See the +`uwsgi documentation ` for +reference. + + +SEE ALSO +-------- +`uWSGI Documentation `_ + +:strong:`cdist-type__netbox`\ (7) +:strong:`cdist-type__netbox_gunicorn`\ (7) + + +AUTHORS +------- +Matthias Stecher + + +COPYING +------- +Copyright \(C) 2020 Matthias Stecher. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__netbox_uwsgi/manifest b/type/__netbox_uwsgi/manifest new file mode 100755 index 0000000..7c593e8 --- /dev/null +++ b/type/__netbox_uwsgi/manifest @@ -0,0 +1,86 @@ +#!/bin/sh -e +# __netbox_uwsgi/manifest + +# Check states +state="" +unit_state="" +param_state="$(cat "$__object/parameter/state")" + +case "$param_state" in + enabled|disabled) + state="present" + unit_state="$param_state" + ;; + + absent) + state="absent" + unit_state="disabled" + ;; + + *) + # does not exist + printf "The state '%s' does not exist, can't continue!\n" "$param_state" >&2 + exit 2 + ;; +esac + + +mkdir "$__object/files" + +# check if systemd sockets will be used +if [ -f "$__object/parameter/bind-to" ]; then + SYSTEMD_SOCKET="yes" +fi +if find "$__object/parameter/" -maxdepth 1 -name "*-bind" -print -quit | grep -q .; then + SYSTEMD_SOCKET="no" +fi +echo "$SYSTEMD_SOCKET" > "$__object/files/systemd_socket" + +if [ "$state" = "present" ]; then + # already checked outside this if-clause + export SYSTEMD_SOCKET + + PROTOCOL="$(cat "$__object/parameter/protocol")" + export PROTOCOL + + if [ -f "$__object/parameter/serve-static" ]; then + STATIC_MAP="yes" + export STATIC_MAP + fi + + # process template + "$__type/files/uwsgi.ini.sh" > "$__object/files/uwsgi.ini" + + # uwsgi config file + # TODO maybe patching with __key_value cause of .ini ? + __file /opt/netbox/uwsgi.ini \ + --mode 644 --owner netbox \ + --source "$__object/files/uwsgi.ini" + +else + # absent config file + __file /opt/netbox/uwsgi.ini --state absent +fi + + +# handle the systemd socket +if [ "$SYSTEMD_SOCKET" = "yes" ]; then + TYPE="uWSGI" + export TYPE + + # generate and set the socket unit + "$__type/files/netbox.socket.sh" "$__object/parameter/bind-to" \ + > "$__object/files/netbox.socket" + __systemd_unit uwsgi-netbox.socket \ + --state "$state" --enablement-state "$unit_state" \ + --source "$__object/files/netbox.socket" --restart +else + # remove the systemd socket unit + __systemd_unit uwsgi-netbox.socket --state absent +fi + +# install service file +"$__type/files/netbox.service.sh" > "$__object/files/netbox.service" +__systemd_unit uwsgi-netbox.service \ + --state "$state" --enablement-state "$unit_state" \ + --source "$__object/files/netbox.service" --restart diff --git a/type/__netbox_uwsgi/parameter/boolean b/type/__netbox_uwsgi/parameter/boolean new file mode 100644 index 0000000..aa08196 --- /dev/null +++ b/type/__netbox_uwsgi/parameter/boolean @@ -0,0 +1 @@ +serve-static diff --git a/type/__netbox_uwsgi/parameter/default/bind-to b/type/__netbox_uwsgi/parameter/default/bind-to new file mode 100644 index 0000000..c696456 --- /dev/null +++ b/type/__netbox_uwsgi/parameter/default/bind-to @@ -0,0 +1 @@ +127.0.0.1:3031 diff --git a/type/__netbox_uwsgi/parameter/default/protocol b/type/__netbox_uwsgi/parameter/default/protocol new file mode 100644 index 0000000..caf986e --- /dev/null +++ b/type/__netbox_uwsgi/parameter/default/protocol @@ -0,0 +1 @@ +uwsgi diff --git a/type/__netbox_uwsgi/parameter/default/state b/type/__netbox_uwsgi/parameter/default/state new file mode 100644 index 0000000..86981e6 --- /dev/null +++ b/type/__netbox_uwsgi/parameter/default/state @@ -0,0 +1 @@ +enabled diff --git a/type/__netbox_uwsgi/parameter/optional b/type/__netbox_uwsgi/parameter/optional new file mode 100644 index 0000000..3284ccc --- /dev/null +++ b/type/__netbox_uwsgi/parameter/optional @@ -0,0 +1,2 @@ +state +protocol diff --git a/type/__netbox_uwsgi/parameter/optional_multiple b/type/__netbox_uwsgi/parameter/optional_multiple new file mode 100644 index 0000000..3f3e7d4 --- /dev/null +++ b/type/__netbox_uwsgi/parameter/optional_multiple @@ -0,0 +1,5 @@ +bind-to +uwsgi-bind +http-bind +fastcgi-bind +scgi-bind diff --git a/type/__netbox_uwsgi/singleton b/type/__netbox_uwsgi/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__networktime/man.rst b/type/__networktime/man.rst new file mode 100644 index 0000000..41beeb6 --- /dev/null +++ b/type/__networktime/man.rst @@ -0,0 +1,50 @@ +cdist-type__networktime(7) +========================== + +NAME +---- +cdist-type__networktime - Generic time synchronization type + + +DESCRIPTION +----------- + +This type is intended to be a simple abstraction over the various backends and +programs available for network time synchronization. This type only takes a +list of peers to synchronize to as argument, and then chooses an appropriate +backend depending on the operating system, configures, starts and enables it to +start on boot. + +Currently, the following OSes are supported with the following backends: + +- Alpine Linux: builtin busybox NTPd +- Debian/Ubuntu: systemd-timesyncd + + +REQUIRED MULTIPLE PARAMETERS +------------------- +peer: + The name or IP address of a peer to synchronize to. + + +EXAMPLES +-------- + +.. code-block:: sh + + # 2.XXX.ntp.org are IPv6-enabled pools + __networktime --peer 2.ch.pool.ntp.org \ + --peer 2.europe.pool.ntp.org + + +AUTHORS +------- +Joachim Desroches + + +COPYING +------- +Copyright \(C) 2021 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__networktime/manifest b/type/__networktime/manifest new file mode 100755 index 0000000..1febf66 --- /dev/null +++ b/type/__networktime/manifest @@ -0,0 +1,74 @@ +#!/bin/sh -e +# +# 2021 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +os=$(cat "${__global:?}/explorer/os") + +case "$os" in +'alpine') + backend=busybox-openrc + ;; +'debian' | 'ubuntu') + backend=systemd-timesyncd + ;; +*) + printf "__networktime is not yet implemented for %s.\n" "$os" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +case "$backend" in +'busybox-openrc') + argstring="-N" + while read -r peer; + do + argstring="$argstring -p $peer" + done < "${__object:?}/parameter/peer" + + __start_on_boot ntpd + + __file /etc/conf.d/ntpd \ + --mode 0644 --onchange "service ntpd restart"\ + --source - <<- EOF + # NTPd OpenRC configuration file. Managed by cdist. + NTPD_OPTS="$argstring" + EOF + ;; + +'systemd-timesyncd') + peers="$(tr '\n' ' ' < "${__object:?}/parameter/peer")" + + __package ntp --state absent + require="__package/ntp" __systemd_unit systemd-timesyncd \ + --enablement-state enabled --restart + + __file /etc/systemd/timesyncd.conf \ + --mode 0644 --onchange "systemctl restart systemd-timesyncd" \ + --source - <<- EOF + # timesyncd(8) configuration file. Managed by cdist. + [Time] + NTP=$peers + EOF + ;; +*) + printf "Unkown backend in __networktime. This is a bug.\n" >&2 + exit 1 + ;; +esac diff --git a/type/__networktime/parameter/required_multiple b/type/__networktime/parameter/required_multiple new file mode 100644 index 0000000..c9f6d41 --- /dev/null +++ b/type/__networktime/parameter/required_multiple @@ -0,0 +1 @@ +peer diff --git a/type/__networktime/singleton b/type/__networktime/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__nextcloud/explorer/config b/type/__nextcloud/explorer/config new file mode 100755 index 0000000..6637ad6 --- /dev/null +++ b/type/__nextcloud/explorer/config @@ -0,0 +1,29 @@ +#!/bin/sh -e +# __nextcloud/explorer/config + +# Checks the nextcloud configuration + + +# Get the installdir +installdir="/$__object_id" + +# Check if the tools are available +if [ -d "$installdir" ]; then + cd "$installdir" + + # if those files exist, everything should be good + if [ -f "occ" ] && [ -f "config/config.php" ]; then + # Dump out config instead of fuzz every possible option through + # `occ config:system:get`. Or parse through the whole json or + # yaml-like output of `occ config:list system --private`. + # + # shellcheck disable=SC2016 # cause of the php inline code + php -r 'require("lib/private/Config.php"); $config = new OC\Config("config/"); + function printv($key, $value) {printf("%s = %s\n", $key, $value);} + foreach($config->getKeys() as $key){ + $value = $config->getValue($key); + if(is_array($value)) foreach($value as $n => $in) printv($n."|".$key, $in); + else printv($key, $value); + };' + fi +fi diff --git a/type/__nextcloud/explorer/version b/type/__nextcloud/explorer/version new file mode 100755 index 0000000..1e1cda9 --- /dev/null +++ b/type/__nextcloud/explorer/version @@ -0,0 +1,20 @@ +#!/bin/sh -e +# __nextcloud/explorer/version + +# Check the currently installed version. Outputs nothing if nothing found. + + +# Get the install directory +installdir="/$__object_id" + +# Check if the installation directory exists +if [ -d "$installdir" ]; then + cd "$installdir" + + # if those files exist, everything should be good + if [ -f "occ" ] && [ -f "version.php" ]; then + # Detect php version with the version file. + # shellcheck disable=SC2016 # cause of the php inline code + php -r 'require("version.php"); print($OC_VersionString);' + fi +fi diff --git a/type/__nextcloud/gencode-remote b/type/__nextcloud/gencode-remote new file mode 100755 index 0000000..6812c68 --- /dev/null +++ b/type/__nextcloud/gencode-remote @@ -0,0 +1,257 @@ +#!/bin/sh -e +# __nextcloud/gencode-remote + +# Install if not installed + +# Legacy: +# curl -sS -L '$nextcloud_uri' | tar xj --strip-components=1 nextcloud/ + + +# Call the nextcloud occ script as the designed user. Maybe this can be a bit +# more effictive with user switching, but currently the easiest way of doing +# it. +# +# All arguments are directly passed to occ (injection alarm ;-) ) +occ() { + # su creates a new shell, so it does not affect the current session + # will not use -q as it supresses errors, too + cat << SHELL +su -s /bin/sh -l "$user" -- -e <<'SU' +cd '$installdir' && php occ --no-warnings --no-interaction --no-ansi $@ +SU +SHELL +} + +# Turn the maintainer mode on, but print it only once at all. +# +# No arguments. +occ_maintainer_mode_on() { + # Check if this was not already done + if [ "$_maintainer_mode_on" != "yes" ]; then + occ maintenance:mode --on + _maintainer_mode_on="yes" + fi +} + +# Print the value of the given configuration. +# +# Arguments: +# 1: the nextcloud configuration name +getparam() { + awk -v FS=" = " -v name="$1" ' + function ntostring(n) { ret=""; for(i=n; i<=NF; i++) ret=ret $i (i> "$__messages_out" + +# Apply some misc to the installation folder. +elif [ "$install" ]; then + # Maintainer mode is not available before installation + + # Correct all file permissions of the new installation + cat << REMOTE +chown '$user':'$group' -R '$installdir' +REMOTE +fi + + +# Check if the nextcloud application needs to be installed. +# This checks the state of the configuration, not of the directory. +# +# shellcheck disable=SC2089 # disabled to write args string +if ! grep -q -F "installed = 1" "$__object/explorer/config"; then + # argument construction + occ_install_args="" + + # Error function if value not found + die_err() { + echo "parameter not found but required; can't continue!!" >&2 + exit 1 + } + # Database setup for mysql and pgsql + db_setup() { + # add type and other database values + occ_install_args="$occ_install_args --database '$1'" + occ_install_args="$occ_install_args --database-host '$(cat "$__object/parameter/database-host" || die_err)'" + occ_install_args="$occ_install_args --database-name '$(cat "$__object/parameter/database-name" || die_err)'" + occ_install_args="$occ_install_args --database-user '$(cat "$__object/parameter/database-user" || die_err)'" + occ_install_args="$occ_install_args --database-pass '$(cat "$__object/parameter/database-password" || die_err)'" + + db_prefix="$__object/parameter/database-prefix" + if [ -f "$db_prefix" ]; then + occ_install_args="$occ_install_args --database-table-prefix '$(cat "$db_prefix")'" + fi + } + + database_type="$(cat "$__object/parameter/database-type")" + case "$database_type" in + sqlite3) + occ_install_args="$occ_install_args --database sqlite" + ;; + mysql) + db_setup mysql + ;; + pgsql) + db_setup pgsql + ;; + + *) + printf "Database type '%s' is unkown!\n" "$database_type" >&2 + exit 3 + ;; + esac + + # Admin stuff + occ_install_args="$occ_install_args --admin-pass '$(cat "$__object/parameter/admin-password")'" + + admin_user="$__object/parameter/admin-user" + if [ -f "$admin_user" ]; then + occ_install_args="$occ_install_args --admin-user '$(cat "$admin_user")'" + fi + admin_email="$__object/parameter/admin-email" + if [ -f "$admin_email" ]; then + occ_install_args="$occ_install_args --admin-email '$(cat "$admin_email")'" + fi + + # Data directory + datadir="$__object/parameter/data-directory" + if [ -f "$datadir" ]; then + occ_install_args="$occ_install_args --data-dir '$(cat "$datadir")'" + fi + + + # Execute the install command. + # generated parameters will be splited in the remote shell + occ maintenance:install "$occ_install_args" + + # send install message + echo installed >> "$__messages_out" +fi + + +# Handle the config +mkdir "$__object/files" +"$__type/map-conf-changes.sh" > "$__object/files/conf-cmds" + +# only print if there are changes listed +if [ -s "$__object/files/conf-cmds" ]; then + # save that we did changes + changes="yes" + occ_maintainer_mode_on + + # print change commands incl. the switch of user context + # using -e to abort if the commands failed + printf "su -s /bin/sh -l '%s' -- -e << 'SU'\n" "$user" + printf "cd '%s'\n" "$installdir" + cat "$__object/files/conf-cmds" + printf "SU\n" +fi + + +# Get the current and future data directory +data_old="$(getparam datadirectory)" +data_new="$(cat "$__object/parameter/data-directory" 2>/dev/null || printf "%s/data" "$installdir")" + +# Move if they should be moved. Avoid false positives if $data_old is empty +if [ "$data_old" ] && [ "$data_old" != "$data_new" ]; then + # save that we did changes + changes="yes" + occ_maintainer_mode_on + + # Change the configuration variable and then move the folder. This order is + # important if SQLite is used, but the config already corrupted if it can + # not be moved. + occ config:system:set datadirectory --type=string --value "'$data_new'" + cat << REMOTE +cd '$installdir' # only for the users safety + +rm -rf '$data_new' +mkdir -p '$(dirname "$data_new")' # if the parent not exists +mv -T '$data_old' '$data_new' + +REMOTE +fi + +# Print configured message if changes where done to the configuration +if [ "$changes" ]; then + echo configured >> "$__messages_out" +fi + + +# Check if this is the fist install +if [ "$install" ]; then + # do some convert stuff etc. + + # variable accessible from the last $install if-clause + case "$database_type" in + mysql) + # only available for mysql + occ db:convert-mysql-charset + ;; + esac + + occ db:convert-filecache-bigint +fi + +# Disable maintainer mode +if [ "$_maintainer_mode_on" = "yes" ]; then + occ maintenance:mode --off +fi diff --git a/type/__nextcloud/man.rst b/type/__nextcloud/man.rst new file mode 100644 index 0000000..1e0238d --- /dev/null +++ b/type/__nextcloud/man.rst @@ -0,0 +1,294 @@ +cdist-type__nextcloud(7) +======================== + +NAME +---- +cdist-type__nextcloud - Installs and manages a nextcloud instance + + +DESCRIPTION +----------- +This type installs, upgrades and configure a nextcloud instance. The object +id is the absolute path for the installation directory. Nextcloud will be +installed unter that directory. + + +REQUIRED PARAMETERS +------------------- +version + The version that should be installed. If it is already installed and the + installed version lower, it will upgrade nextcloud if ``--install-only`` is + not set. + + You get version numbers from the `official changelog + `_ or from the `GitHub Releases + `_ page. The type will + download the tarball over the official nextcloud website. + + The type will never downgrade a nextcloud instance. Rather, it will fail, + as this is a missconfiguration. Downgrades are not recommended and + supported by upstream. Such cases can happen if the nextcloud instance was + upgraded via the built-in nextcloud installer. In such cases, it is + recommended to use the ``--install-only`` option. + +admin-password + The administrator password to access the nextcloud instance. Must be given + in plain text. This parameter has no effect if nextcloud will not be + installed. + + +OPTIONAL PARAMETERS +------------------- +mode + Sets the unix file mode of the nextcloud directory. This is not inherited + to child files or folders. Defaults to `755`. + +user + The user which owns the complete nextcloud directory. The php application + should be executed with this user. All nextcloud commands will be executed + with this user. This type will not create the unix user. + + The type assumes the default `www-data` user, which is common on Debian + systems. **If you change this option, please do the same with the group + parameter!** + +group + The group all files and folders of the nextcloud installation should have. + Defaults to `www-data`. Should be changed with ``--user``. + + +BOOLEAN PARAMETERS +------------------ +install-only + Skips all nextcloud upgrades done by this type. Should be used when + nextcloud upgrades are (*exclusively*) done via the built-in updater. + + +NEXTCLOUD CONFIG PARAMETERS +--------------------------- +host + All hostnames where the the users can log into nextcloud. If you access + nextcloud via a hostname not given to this list, the access fails. This + parameter can be set multiple times. + +admin-user + The username of the administrative user which will be created while the + installation. If not set, nextcloud defaults to "admin". This parameter has + no effect if nextcloud will not be installed. + +admin-email + The email address of the administrative user. This parameter has no effect + if nextcloud will not be installed. + +data-directory + This will set or change the data directory where nextcloud will keep all + its data, including the SQLite database if any. By default, it will be + saved in the ``data`` directory below the nextcloud directory. + + If this directory change, this type will move the old location to the new + one to preserve all data. This is not supported by upstream, as some apps + may not handle this. + +database-type + Sets the type of database that should be used as backend. Possible backends + are: + + SQLite + Use ``sqlite3`` as value. Saves everything in a database file + stored in the data directory. It is only recommended for very small + installations or test environments from upstream. + + *All further database options are ignored if SQLite is selected as + database backend.* + + MariaDB + Use ``mysql`` as value. MariaDB and MySQL are threated the same + way. They are the recommended database backends recommended from + upstream. + + PostgreSQL + Use ``pgsql`` as value. + + **This parameter defaults to the SQLite database backend, as it is the + simplest one to setup and do not require extra parameters.** + + If this parameter change, the type will migrate to the new database type. + It will not work for SQLite because the upstream migration script does not + support it. **Be aware that migrations take there time, plan at minimum + 40 seconds of migration for a stock installation.** + +database-host + The database host to connect to. Possible are hostnames, ip addresses or + UNIX sockets. UNIX sockets must set in the format of + ``localhost:/path/to/socket``. If an non-standard port is used, set it + after the hostname or ip address seperated by an colon (``:``). If this + value is not set, nextcloud defaults to the value ``localhost``. + + This type will not migrate data if the type does not change. You must do + this manually by setting the maintainer mode (to avoid data changes) and + then cloning the database to the new destination. After that, run cdist to + apply the config changes. It should automaticly remove the maintainer mode. + +database-name + The name of the database to connect to. Required if MariaDB or PostgreSQL + is used. + +database-user + The username to access the database. Required if MariaDB or PostgreSQL is + used. + +database-password + The password required to authorize the given user. Required if MariaDB or + PostgreSQL is used. + +database-prefix + The table prefix used by nextcloud. If nothing set, nextcloud defaults to + ``oc_``. + + +MESSAGES +-------- +installed + Nextcloud was successfully installed. + +upgraded $old to $new + The nextcloud version was upgraded from `$old` to `$new`. + +configured + Nextcloud configuration was changed. + + +ABORTS +------ +Aborts in the following cases: + +The current installed version is greather than the version that should be +installed. See the parameter description of `--version` for detailed +information. The problem can be fixed by bumping the version value to at least +the version that is currently installed or use the parameter `--install-only`. + +It may abort if the data directory can not be moved correctly. Then, the +nextcloud configuration is broken and must be resolved manually: Move the data +directory to the correct location or change the configuration to point to the +old destination and retry. + +It aborts if it should migrate to a SQLite database. This will be done before +the upstream migration script is executed, as it would throw the same error. + +The explorers will abort if they found a valid nextcloud installation, but no +installed `php`. Currently, this is intended behaviour, because it can not +safely get the current nextcloud version, also do not get the nextcloud +configuration. For more information, see the *NOTES section*. + + +EXAMPLES +-------- + +.. code-block:: sh + + # minimal nextcloud installation with sqlite and other defaults + # please only use sqlite for minimal or test installations as recommend :) + __nextcloud /var/www/html/nextcloud --version 20.0.0 \ + --admin-password "iaminsecure" \ + --host localhost --host nextcloud + + # installation under the webroot + __nextcloud /var/www/html/ --version 20.0.0 + --admin-password "notthatsecure" --host mycloud.example.com + + # more extensive configuration + __nextcloud /var/www/cloud --version 20.0.0 --admin-password "iaminsecure" \ + --host localhost --host nextcloud --host 192.168.1.67 \ + --data-directory /var/lib/nextcloud/what \ + --database-type mysql --database-host "localhost" --database-name "nextcloud" \ + --database-user "test" --database-password "not-a-good-password" + + +NOTES +----- +This cdist type does not cover all configuration options that nextcloud offer. +If you need more configuration options for nextcloud, you are welcome to extend +this type and contribute it upstream! + +- `Nextcloud configuration reference + `_ + +Currently, the state of this object is always `present`. So it will always be +installed without the option to uninstall it again (`absent`). This was done +because it will not be a common demand to uninstall nextcloud again. If you +need to toggle the state, you are welcome to contirbute! + +Parameters given for the admin user which will be set up at installation time +(`--admin-*` ones) are not applied if nextcloud will not be installed. +Therefor, parameter changes are not applied to the installation. Currently not +implemented - but possible - is to use the type +:strong:`cdist-type__nextcloud_user`\ (7) to do all the later work. + +Database migration is only partly supported if the database will be changed to +``mysql`` or ``pgsql``, because it is supported by an upstream script. You are +welcome to extend this type for database migrations between the same database +type. For an implementation, you may use shell utilites like ``mysqldump(1)`` +(be aware that this may not already be installed) or use the already installed +php code to migrate. + +The type will abort if a valid nextcloud directory already exists in the +explorer execution, but no `php` exists to explore the setup. Therefor, the +manifest could not install `php` yet. This is not the case for a new +installation, as there does not exist a nextcloud directory with a valid +structure. While some code could be skipped and the other replaced with `awk` +with something like +``awk '$1 == "$OC_VersionString" {gsub(/['\'';]/, "", $3); print $3}' version.php``, +it is not handled for the following cases: + +1. This case should not happen very often. +2. Maybe because of ``libapache2-mod-php`` or ``php-fpm``, `php` already + exists for the cli. +3. While the `awk` replacement for the version is just a bit worser, it would + bring stable results, while it would be more difficult to dump out the + configuration without custom `php` or the help from ``php occ``. Therefor, + it would make false assumptions like it want to install nextcloud again, + do not delete configuration options and set all available nextcloud options + that are available through this type. + +If the nextcloud installation does not work and you stuck in a plaintext error +screen, try to restart your Apache WWW server first! This type will install all +php dependencies, but there are not recognised by the server-internal php +environment. This can happen after a database migration between different +database types, as it installs the database module only when it is required. + +If the tarball needs to be downloaded, it will be directly downloaded into the +directory ``/tmp`` and will be unpacked to the destination for an installation +or to the same directory but prefixed with a dot for an update. It will +download it into the temp directory because it does not find a better location. +In legacy, it was downloaded to the parent directory, but this may not the best +location as the installation dir can be everywhere. + +This type does not garantee to always show the maintenance mode screen because +nextcloud does not show it in every case: + +1. For fresh installations, the maintenance mode can not be set. +2. While upgrades starting at version 20, the user is promted to execute the + update manually via the webinterface instead of the maintenance screen. + +It is recommended to show an own maintanance screen via the webserver if this +is critical for you. + + +SEE ALSO +-------- +`Nextcloud documentation `_ + +:strong:`cdist-type__nextcloud_user`\ (7) + + +AUTHORS +------- +Matthias Stecher + + +COPYING +--------- +Copyright \(C) 2020 Matthias Stecher. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__nextcloud/manifest b/type/__nextcloud/manifest new file mode 100755 index 0000000..90508d8 --- /dev/null +++ b/type/__nextcloud/manifest @@ -0,0 +1,134 @@ +#!/bin/sh -e +# __nextcloud/manifest + + +# Version compare function original from __sensible_editor +# +# Arguments: +# 1: version of which $2 should be checked against +# 2: version which should be bigger than or equal with $1 +# +# Return code: +# 0: $1 is bigger than $2 +# 1-n: $1 is smaller than or equal $2 +version_ge() { + printf "%s" "$1" | awk -F '[^0-9.]' -v target="$2" ' + function max(x, y) { return x > y ? x : y } + BEGIN { + getline + nx = split($1, x, ".") + ny = split(target, y, ".") + for (i = 1; i <= max(nx, ny); ++i) { + diff = int(x[i]) - int(y[i]) + if (diff == 0) continue + exit (diff < 0) + } + exit 1 + }'; return $? +} + + +# Check support status +os="$(cat "$__global/explorer/os")" + +case "$os" in + debian|ubuntu) + # PHP main + __package php-cli + # to unpack the package + __package bzip2 + # install misc packages for nextcloud + __package ffmpeg + + # PHP modules + for package in php-gd php-json php-mysql php-curl php-mbstring php-intl \ + php-imagick php-xml php-zip php-bz2 php-bcmath php-gmp + do + require="__package/php-cli" __package $package + done + + # check support database additions (but don't remove junk of old ones) + case "$(cat "$__object/parameter/database-type")" in + sqlite|sqlite3) + __package php-sqlite3 + ;; + mysql|mariadb) + __package php-mysql + ;; + pgsql|postgres|postgresql) + __package php-pgsql + ;; + esac + ;; + + # unkown distro - what to install? + *) + printf "unkown %s, don't know what to install ..\n" "$os" >&2 + echo "checkout the __nextcloud/manifest to contribute a working package list" >&2 + exit 1 + ;; +esac + + +# Get the user and group +mode="$(cat "$__object/parameter/mode")" +user="$(cat "$__object/parameter/user")" +group="$(cat "$__object/parameter/group")" + +# Get the installation directory +installdir="/$__object_id" + +# Set permissions after the nextcloud installation/upgrade is done +# FIXME maybe less strict if some parameter is not given by the user? +# permissions also partily set via the gencode-remote +require="__nextcloud/$__object_id" __directory "$installdir" \ + --mode "$mode" --owner "$user" --group "$group" + + +# Get version information +version_is="$( cat "$__object/explorer/version" )" +version_should="$( cat "$__object/parameter/version" )" +# The version URI +nextcloud_uri="https://download.nextcloud.com/server/releases/nextcloud-${version_should}.tar.bz2" +nextcloud_sum="${nextcloud_uri}.sha256" + + +# Check if there is a current installation. It depends where the upstream +# tarball should be unpacked (directly or moved in a later stage). +if [ "$version_is" ]; then + # Only set and check the version if a upgrade is allowed. + # if this block will be skipped, no upgrade will be done + if ! [ -f "$__object/parameter/install-only" ]; then + # Block downgrades as there are may caused from the automatic upgrader + # if the current version is higher than the version that should be installed + if version_ge "$version_is" "$version_should"; then + # it's an error if the current version is higher than the one that should be installed + printf "The current nextcloud version '%s' is higher than the version that should be installed (%s)\n" \ + "$version_is" "$version_should" >&2 + printf "Please bump the nextcloud version to '%s' or higher!\n" "$version_is" >&2 + exit 2 + fi + + # Set destination to a temporary directory + destination="$(dirname "$installdir")/.$(basename "$installdir")" + fi +else + # Set destination to the real destination + destination="$installdir" +fi + +# Install/Upgrade the nextcloud version if there is a destination set. +# it checks if it is necessary and intended to upgrade +if [ "$destination" ] && [ "$version_is" != "$version_should" ]; then + # download it to the tmp directory + # FIXME --sum is currently rather a hack, see cdist#844 + __download "/tmp/nextcloud-${version_should}.tar.bz2" \ + --url "$nextcloud_uri" \ + --sum "sha256:$(curl -sS -L "$nextcloud_sum" | awk '{print $1}')" + + # after this, unpack it from /tmp to $destination + require="__download/tmp/nextcloud-${version_should}.tar.bz2" \ + __unpack "/tmp/nextcloud-${version_should}.tar.bz2" \ + --tar-strip 1 \ + --destination "$destination" +fi diff --git a/type/__nextcloud/map-conf-changes.sh b/type/__nextcloud/map-conf-changes.sh new file mode 100755 index 0000000..9b6ffe3 --- /dev/null +++ b/type/__nextcloud/map-conf-changes.sh @@ -0,0 +1,316 @@ +#!/bin/sh -e +# __nextcloud/map-conf-changes.sh + + +# The environment variable "$install" should be set if nextcloud was installed +# now. This changes the behaviour to not trust gathered values from the +# explorer. + + +# Print the value of the given configuration. +# +# Arguments: +# 1: the nextcloud configuration name +# +# Returns with a unsuccessful return code if no parameter found. +getparam() { + awk -v FS=" = " -v name="$1" ' + function ntostring(n) { ret=""; for(i=n; i<=NF; i++) ret=ret $i (i&2 + exit 4 + fi + + if paramexist "$2"; then + # remove it because it exists + printf "php occ config:system:delete '%s'\n" "$2" + fi + fi +} + +# Set's the cdist parameter value to nextcloud as specific value. +# +# Arguments: +# 1: cdist type parameter name +# 2: nextcloud config name +# 3: conditional mandatory of this parameter; value "required" if true +# 4: default value; will be used if parameter is absent +conf_string() { + conf_base "$1" "$2" "$3" "set '%s' --type=string --value='%s'" "$4" +} +conf_number() { + conf_base "$1" "$2" "$3" "set '%s' --type=integer --value='%s'" "$4" +} +conf_decimal() { + conf_base "$1" "$2" "$3" "set '%s' --type=double --value='%s'" "$4" +} + +# Sets the nextcloud configuration option after a boolean cdist parameter. +# +# Arguments: +# 1: cdist type parameter name +# 2: nextcloud config name +conf_boolean() { + # map parameter to a php boolean (are outputted as 0 or 1) + if [ -f "$__object/parameter/$1" ]; then + testval="1" + value="true" + else + testval="0" + value="false" + fi + + if ! testparam "$2" "$testval"; then + # set it if does not already exist + printf "php occ config:system:set '%s' --type=boolean --value=%s\n" "$2" "$value" + fi +} + +# Corrects the array after all values given by the parameter. Values not given +# to this type will be removed. +# +# Arguments: +# 1: cdist type parameter name +# 2: nextcloud config name +# 3: conditional mandatory of this parameter; value "required" if true +# FIXME currently no default value due to complexity of arrays +conf_array() { + if [ -f "$__object/parameter/$1" ]; then + # reset array if installation is fresh + if [ "$install" ]; then + # just remove everything, because we don't know it + printf "php occ config:system:delete '%s' || true\n" "$2" + + # counter is zero for sure + counter=0 + + # else, default behaviour of the array + else + # save counter of the next free index + # shellcheck disable=SC1004 # the \ is required for awk + counter=$( awk -v FS=" = " -v name="$2" ' + BEGIN { counter = 0 } + split($1, header, "|") == 2 && header[1] ~ /^[[:digit:]]+$/ && header[2] == name \ + { if(counter < header[1]) counter = header[1] } + END { print counter + 1 } + ' "$__object/explorer/config" + ) + + # create a file which contains all lines not already resolved by this function + _dir="$__object/files/conf-arrays" + mkdir -p "$_dir" + grep "^[[:digit:]]*|$2 = " "$__object/explorer/config" > "$_dir/$2" || true # ignore not found + fi + + # iterate through every value + while read -r value; do + # check every value if he exists + if ! grep -q "^[[:digit:]]*|$2 = $value$" "$__object/explorer/config"; then + # add this value + printf "php occ config:system:set '%s' '%s' --type=string --value='%s'\n" \ + "$2" "$(( counter ))" "$value" + counter=$(( counter + 1 )) + fi + + if [ -z "$install" ]; then + # removes it from the list of unhandled values + grep -v "^[[:digit:]]*|$2 = $value$" "$_dir/$2" > "$_dir/$2_tmp" || true # ignore not found + mv "$_dir/$2_tmp" "$_dir/$2" # because we can't do `cat foo > foo` + fi + done < "$__object/parameter/$1" + + if [ -z "$install" ]; then + # interate through the leftover values + # remove them, as they should not exist (at least can be) + # + # shellcheck disable=SC2034 # $equal left for readability + while read -r start equal value; do + # remove those specific elements from the array + printf "php occ config:system:delete '%s' '%s' --error-if-not-exists\n" \ + "$2" "$( printf "%s" "$start" | awk -F'|' '{print $1}' )" + done < "$_dir/$2" + fi + else + if [ "$3" = "required" ]; then + # error because the parameter should be set + printf "Parameter '%s' not set by user, but required!\n" "$1" >&2 + exit 4 + fi + + # remove everything because we don't know which was set by the user + if paramexist "$2"; then + # remove the whole array + printf "php occ config:system:delete '%s'\n" "$2" + fi + fi +} + +# Migrate the database to a new database type +# +# Arguments: +# 1: the database type to convert to +migrate_db() { + # from argument + database_type="$1" + + # hostname, database, username and password + database_host="$(cat "$__object/parameter/database-host" 2>/dev/null || printf "localhost")" + database_name="$(cat "$__object/parameter/database-name")" + database_user="$(cat "$__object/parameter/database-user")" + database_pass="$(cat "$__object/parameter/database-password")" + + # Extract the port from the host + # this is required for pgsql, but mysql can do it itself, too + if printf "%s" "$database_host" | grep -q ":[[:digit:]]\+$"; then + # extract the last part, which is the port number + database_port="${database_host##*:}" + else + # set default port because the tool can not do this for pgsql + # it looks like mysql get struggles, too + case "$database_type" in + mysql) + database_port=3306 + ;; + pgsql) + database_port=5432 + ;; + esac + + # Correct this value to the value set by the parameter + # this will prevent codegen in the run after the migration + correct_standard_port="yes" + fi + + # print out the correct command + printf "php occ db:convert-type --no-interaction --no-ansi --clear-schema --all-apps \ + '%s' '%s' --password '%s' '%s' --port '%u' '%s'\n" \ + "$database_type" "$database_user" "$database_pass" "$database_host" "$database_port" "$database_name" + printf "php occ maintenance:mode --on\n" # was disabled by database convertion + + # Correct the database host value if it was not correctly set by the migration script + if [ "$correct_standard_port" = "yes" ]; then + printf "php occ config:system:set '%s' --type=string --value '%s'\n" "dbhost" "$database_host" + fi +} + + +# Set the install variable if nextcloud was not installed before this type. +if ! testparam installed 1; then + install="yes" +fi + + +# Map all parameters + +# Generate the config changes + +# misc +conf_array host trusted_domains + +# If already set via the installer, we don't need to do this +# set default values from the nextcloud installer to do not override them +if [ -z "$install" ]; then + # Database to check if the type changed + # use the current type if no old type found to match instead of migrate + database_type="$(cat "$__object/parameter/database-type")" + old_db_type="$(getparam dbtype || printf "%s" "$database_type")" + + case "$database_type" in + sqlite3) + if [ "$old_db_type" != "sqlite3" ]; then + echo "Migrating to a SQLite database is not supported by upstream!" >&2 + echo "Do it manually or reinstall nextcloud .." >&2 + exit 1 + fi + conf_string database-type dbtype + ;; + + mysql|pgsql) + if [ "$old_db_type" != "$database_type" ]; then + # the migration will change all database parameters itself + migrate_db "$database_type" + else + # no change of dbtype cause it will cause a migration + conf_string database-host dbhost installdef "localhost" + conf_string database-name dbname required + conf_string database-user dbuser required + conf_string database-password dbpassword required + fi + + # It may not be a good idea to change this parameter, but do what + # the user want to do. + conf_string database-prefix dbtableprefix + ;; + + *) + printf "Databasetype '%s' is unkown!\n" "$database_type" >&2 + exit 3 + ;; + esac + + # data-dir is handled in the gencode-remote + #conf_string data-directory datadirectory installdef "/$__object_id/data" +fi diff --git a/type/__nextcloud/parameter/boolean b/type/__nextcloud/parameter/boolean new file mode 100644 index 0000000..0853f49 --- /dev/null +++ b/type/__nextcloud/parameter/boolean @@ -0,0 +1 @@ +install-only diff --git a/type/__nextcloud/parameter/default/database-type b/type/__nextcloud/parameter/default/database-type new file mode 100644 index 0000000..8b2f60c --- /dev/null +++ b/type/__nextcloud/parameter/default/database-type @@ -0,0 +1 @@ +sqlite3 diff --git a/type/__nextcloud/parameter/default/group b/type/__nextcloud/parameter/default/group new file mode 100644 index 0000000..5bbad18 --- /dev/null +++ b/type/__nextcloud/parameter/default/group @@ -0,0 +1 @@ +www-data diff --git a/type/__nextcloud/parameter/default/mode b/type/__nextcloud/parameter/default/mode new file mode 100644 index 0000000..20610ea --- /dev/null +++ b/type/__nextcloud/parameter/default/mode @@ -0,0 +1 @@ +755 diff --git a/type/__nextcloud/parameter/default/user b/type/__nextcloud/parameter/default/user new file mode 100644 index 0000000..5bbad18 --- /dev/null +++ b/type/__nextcloud/parameter/default/user @@ -0,0 +1 @@ +www-data diff --git a/type/__nextcloud/parameter/optional b/type/__nextcloud/parameter/optional new file mode 100644 index 0000000..b51ef3d --- /dev/null +++ b/type/__nextcloud/parameter/optional @@ -0,0 +1,12 @@ +mode +user +group +database-type +database-host +database-name +database-user +database-password +database-prefix +admin-user +admin-email +data-directory diff --git a/type/__nextcloud/parameter/optional_multiple b/type/__nextcloud/parameter/optional_multiple new file mode 100644 index 0000000..c70dc2d --- /dev/null +++ b/type/__nextcloud/parameter/optional_multiple @@ -0,0 +1 @@ +host diff --git a/type/__nextcloud/parameter/required b/type/__nextcloud/parameter/required new file mode 100644 index 0000000..3e83467 --- /dev/null +++ b/type/__nextcloud/parameter/required @@ -0,0 +1,2 @@ +version +admin-password diff --git a/type/__nextcloud_app/explorer/state b/type/__nextcloud_app/explorer/state new file mode 100755 index 0000000..d7572ce --- /dev/null +++ b/type/__nextcloud_app/explorer/state @@ -0,0 +1,38 @@ +#!/bin/sh -e +# __nextcloud_app/explorer/state + +# Outputs the current state of the app. There are: +# - `enabled` if the app is enabled +# - `disabled` if the app is disabled +# - `absent` if the app does not exist +# - nothing if nextcloud is not installed + + +# Get the app id +appid="$__object/parameter/appid" +if [ -f "$appid" ]; then + appid="$(cat "$appid")" +else + appid="$__object_id" +fi + +# Get the installation directory +cloud="$(cat "$__object/parameter/cloud")" +www_user="$(cat "$__object/parameter/www-user")" + + +# Check if the installation directory exists +if [ -d "$cloud" ]; then + # if those files exist, everything should be fine + if [ -f "$cloud/occ" ] && [ -f "$cloud/config/config.php" ]; then + # Check if the app exists in the correct user context + su -s /bin/sh -l "$www_user" -- -e <&2 + echo "Use the type __nextcloud to ensure the installation and mark it as dependency for this type!" >&2 + exit 2 +fi + + +# Check if the state changes +if [ "$state_is" != "$state_should" ]; then + # check what to do + case "$state_should" in + enabled) + if [ "$state_is" = "disabled" ]; then + occ app:enable "'$appid'" + echo enabled >> "$__messages_out" + else + occ app:install "'$appid'" + echo installed >> "$__messages_out" + fi + ;; + + disabled) + if [ "$state_is" = "absent" ]; then + occ app:install --keep-disabled "'$appid'" + echo installed >> "$__messages_out" + else + occ app:disable "'$appid'" + echo disabled >> "$__messages_out" + fi + ;; + + present) + if [ "$state_is" = "absent" ]; then + occ app:install "'$appid'" + echo installed >> "$__messages_out" + fi + # else, everything is ok + ;; + + absent) + occ app:remove "'$appid'" + echo removed >> "$__messages_out" + ;; + esac +fi diff --git a/type/__nextcloud_app/man.rst b/type/__nextcloud_app/man.rst new file mode 100644 index 0000000..9074b03 --- /dev/null +++ b/type/__nextcloud_app/man.rst @@ -0,0 +1,138 @@ +cdist-type__nextcloud_app(7) +============================ + +NAME +---- +cdist-type__nextcloud_app - Managese a Nextcloud app installation + + +DESCRIPTION +----------- +This types manages an app for a Nextcloud installation. For now, you can only +(un-)install or enable/disable an app. + +The object id is the appid of the app which will be managed by this type. It +will be overwritten by the parameter `--appid`. See this parameter for more +information about the appid. + + +REQUIRED PARAMETERS +------------------- +cloud + The absolute path of the Nextcloud installation. + + +OPTIONAL PARAMETERS +------------------- +state + The state of the app. Can be the following: + + present *(default)* + The app is installed. + + enabled + The app is installed and enabled. + + disabled + The app is installed, but disabled. + + absent + The app is not installed. + +appid + The appid is the uniquie identifier for an app in the Nextcloud app store. + It is required to know which app should be installed, which is expressed + via the appid. Apps who are shipped by the installation can not be removed. + Doing this will throw an error at exeuction time. + + To find the appid, you must select the app in the Nextcloud app menu or on + the app page in the Nextcloud app store. Then, examine the URL and use the + lastest part (e.g. "the filename") as appid. + +www-user + The unix user which will be used to execute Nextcloud related stuff. You + should always use the same user for all Nextcloud interactions, for the + webserver and cli execution. As default, `www-data` will be used. + + +MESSAGES +-------- +installed + The app was installed. + +enabled + The app is already installed and was enabled. + +disabled + The app is already installed and was disabled. + +removed + The app was removed. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Nextcloud base installation + __nextcloud /var/www/html/cloud $args + + # install the music app + require="__nextcloud/var/www/html/cloud" __nextcloud_app music \ + --cloud /var/www/html/cloud/ --state enabled + + # enable a shipped app (already installed) + require="__nextcloud/var/www/html/cloud" __nextcloud_app files_external \ + --cloud /var/www/html/cloud/ --state enabled + + # remove some app + require="__nextcloud/var/www/html/cloud" __nextcloud_app drawio \ + --cloud /var/www/html/cloud/ --state absent + + + # Different cloud + __nextcloud /var/www/html/nextcloud $args + # but same app name + require="__nextcloud/var/www/html/nextcloud" __nextcloud_user next_music \ + --cloud /var/www/html/nextcloud/ --appid music + + +NOTES +----- +Currently, it manages just if the app is installed and enabled. Further +implementation is possible, but not done yet. This contains the management of +the app settings (via ``occ config:app:*``) and further finetuning to the +possibilities of installation and enablement (force-enable an app or restrict +enablement only to some groups). + +Special app settings could also be written as a new type which completly +handles this one app with all configuration options. + +Upgrading an Nextcloud app may be possible, but not the scope of this type. +Also, the upgrade can not be done to a given version, which results that this +type will loose the control over the state of the app. Installing the app +manually or hooking into the Nextcloud code is too unsafe and complex, in +addition it will be used rarely. Most admins would propably just update the app +via the web interface. + + +SEE ALSO +-------- +`Nextcloud app store `_ + +:strong:`cdist-type__nextcloud`\ (7) +:strong:`cdist-type__nextcloud_user`\ (7) + + +AUTHORS +------- +Matthias Stecher + + +COPYING +------- +Copyright \(C) 2020 Matthias Stecher. +You can redistribute it and/or modify it under the terms of the GNU +General Public License as published by the Free Software Foundation, +either version 3 of the License, or (at your option) any later version. diff --git a/type/__nextcloud_app/parameter/default/state b/type/__nextcloud_app/parameter/default/state new file mode 100644 index 0000000..e7f6134 --- /dev/null +++ b/type/__nextcloud_app/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/type/__nextcloud_app/parameter/default/www-user b/type/__nextcloud_app/parameter/default/www-user new file mode 100644 index 0000000..5bbad18 --- /dev/null +++ b/type/__nextcloud_app/parameter/default/www-user @@ -0,0 +1 @@ +www-data diff --git a/type/__nextcloud_app/parameter/optional b/type/__nextcloud_app/parameter/optional new file mode 100644 index 0000000..0f2a3eb --- /dev/null +++ b/type/__nextcloud_app/parameter/optional @@ -0,0 +1,3 @@ +state +appid +www-user diff --git a/type/__nextcloud_app/parameter/required b/type/__nextcloud_app/parameter/required new file mode 100644 index 0000000..c3de202 --- /dev/null +++ b/type/__nextcloud_app/parameter/required @@ -0,0 +1 @@ +cloud diff --git a/type/__nextcloud_user/explorer/password b/type/__nextcloud_user/explorer/password new file mode 100755 index 0000000..88260ec --- /dev/null +++ b/type/__nextcloud_user/explorer/password @@ -0,0 +1,49 @@ +#!/bin/sh +# __nextcloud/explorer/password + +# Checks if the given password is working by hacking somehow into the nextcloud +# php libary. +# +# Outputs: +# - "noop" if no password given as parameter +# - "matched" if the given parameter matched the password +# - "mismatched" if the given parameter did not matched +# - "" if no nextcloud directory could be detected + + +# Check if the password exists, else this is nonsense +password="$__object/parameter/password" +if [ -f "$password" ]; then + password="$(cat "$password")" +else + # no password to compare - it's managed by someone other + echo noop + exit +fi + +# Get parameters +user="$__object/parameter/user" +if [ -f "$user" ]; then + user="$(cat "$user")" +else + user="$__object_id" +fi +cloud="$(cat "$__object/parameter/cloud")" +www_user="$(cat "$__object/parameter/www-user")" + + + +# Check if there exists the installation +if [ -d "$cloud" ]; then + # if those files exist, everything should be good + if [ -f "$cloud/occ" ] && [ -f "$cloud/config/config.php" ]; then + # Output the information from the custom php + # change the user to be on the safe side if something is written + su -s /bin/sh -l "$www_user" -- -e <getUserSession()->getManager()->checkPasswordNoLogging("$user", getenv("pw")) ? "matched" : "mismatched");' +SU + fi +fi diff --git a/type/__nextcloud_user/explorer/user b/type/__nextcloud_user/explorer/user new file mode 100755 index 0000000..face683 --- /dev/null +++ b/type/__nextcloud_user/explorer/user @@ -0,0 +1,45 @@ +#!/bin/sh -e +# __nextcloud_user/explorer/user + +# Outputs the raw nextcloud command output of the given user. +# +# The output is extended by the following fields (in the same syntax): +# 1. quota_param which outputs the real quota value instead of resolved values + + +# Parameters +user="$__object/parameter/user" +if [ -f "$user" ]; then + user="$(cat "$user")" +else + user="$__object_id" +fi +cloud="$(cat "$__object/parameter/cloud")" +www_user="$(cat "$__object/parameter/www-user")" + + +# Check if there exists the installation +if [ -d "$cloud" ]; then + # if those files exist, everything should be good + if [ -f "$cloud/occ" ] && [ -f "$cloud/config/config.php" ]; then + # Content could be gathered through php code directly, too. This can + # be done if more parameters are required than user:info will output + # or if there will be too much fuzz in the output. + + # Output the information of the user + # type will abort if explorer is empty, not if occ aborts + su -s /bin/sh -l "$www_user" -- -e <getUserSession()->getManager()->userExists("$user") ? 0 : 1);' +then + php occ --no-warnings --no-interaction --no-ansi --output=plain user:info '$user' + # also output the quota parameter + printf " - quota_param: %s\n" \ + "\$(php occ --no-warnings --no-interaction --no-ansi user:setting '$user' files quota)" +fi +SU + fi +fi diff --git a/type/__nextcloud_user/gencode-remote b/type/__nextcloud_user/gencode-remote new file mode 100755 index 0000000..c76f74e --- /dev/null +++ b/type/__nextcloud_user/gencode-remote @@ -0,0 +1,249 @@ +#!/bin/sh -e +# __nextcloud_user/gencode-remote + + +# Call the nextcloud occ script as the designed user. Maybe this can be a bit +# more effictive with user switching, but currently the easiest way of doing +# it. +# +# All arguments are directly passed to occ (injection alarm ;-) ) +occ() { + # su creates a new shell, so it does not affect the current session + # will not use -q as it supresses errors, too + cat << SHELL +su -s /bin/sh -l "$www_user" -- -e <<'SU' +cd '$cloud' && php occ --no-warnings --no-interaction --no-ansi $@ +SU +SHELL +} + +# Creates the output for the nextcloud command to create a user. Takes all +# required parameters from existing variables. +occ_create() { + cat <> "$__messages_out" + else + occ_create + echo created >> "$__messages_out" + fi + ;; + + disabled) + if [ "$state_is" = "absent" ]; then + occ_create + echo created >> "$__messages_out" + fi + + occ user:disable "'$user'" + echo disabled >> "$__messages_out" + ;; + + present) + if [ "$state_is" = "absent" ]; then + occ_create + echo created >> "$__messages_out" + fi + # else, everything is ok + ;; + + absent) + occ user:delete "'$user'" + echo removed >> "$__messages_out" + ;; + esac +fi + +# Check if the user should not be modified further from the initial setup. +if [ -f "$__object/parameter/only-setup" ]; then + ignore_config="yes" +fi + + +# Check if some user configuration should be changed +# do not run this code if the user will be created in the previous code +if [ "$state_should" != "absent" ] && [ "$ignore_config" != "yes" ]; then + if ! [ -f "$__object/parameter/keep-displayname" ]; then + # Check if the display name is correct if someone is set + if [ -f "$__object/parameter/displayname" ]; then + displayname="$(cat "$__object/parameter/displayname")" + if ! match_param display_name "$displayname"; then + cat <getUserSession()->getManager()->get("$user")->setDisplayName("$displayname") + or print("Couldn'\''t modify $user display name! Maybe unsupported or already set ..".PHP_EOL) + and die(1);' +SU +SHELL + fi + fi + # the display name can not be unset + fi + + if ! [ -f "$__object/paramter/keep-email" ]; then + # Check if the email address is correct + if [ -f "$__object/parameter/email" ]; then + email="$(cat "$__object/parameter/email")" + if ! match_param email "$email"; then + occ user:setting -- "'$user'" settings email "'$email'" + fi + else + # remove if it doesn't exist + if ! match_param email ""; then + occ user:setting --delete -- "'$user'" settings email + fi + fi + fi + + if ! [ -f "$__object/parameter/keep-password" ]; then + # Check state of the password + # explorer handles missing passwords already + if [ "$(cat "$__object/explorer/password")" = "mismatched" ]; then + cat < "$__object/files/explorer_groups" + + # Add/Remove groups not set via the parameter + if [ -s "$__object/parameter/group" ]; then + # Get all groups to remove + grep -Fxv -f "$__object/parameter/group" \ + "$__object/files/explorer_groups" > "$__object/files/group.del" || true + # Get all groups to add + grep -Fxv -f "$__object/files/explorer_groups" \ + "$__object/parameter/group" > "$__object/files/group.add" || true + + # No user groups at all if nothing wanted by the user + else + # remove all groups to stay inline with the user parameter + cp "$__object/files/explorer_groups" "$__object/files/group.del" + fi + + # Remove all groups not exist anymore + if [ -s "$__object/files/group.del" ]; then + while read -r GROUP; do + occ group:removeuser "'$GROUP'" "'$user'" + done < "$__object/files/group.del" + fi + + # Add all existing groups + if [ -s "$__object/files/group.add" ]; then + while read -r GROUP; do + occ group:adduser "'$GROUP'" "'$user'" + done < "$__object/files/group.add" + fi + fi + + + # These parameters are only set if they exist + # ... +fi diff --git a/type/__nextcloud_user/man.rst b/type/__nextcloud_user/man.rst new file mode 100644 index 0000000..200769f --- /dev/null +++ b/type/__nextcloud_user/man.rst @@ -0,0 +1,215 @@ +cdist-type__nextcloud_user(7) +============================= + +NAME +---- +cdist-type__nextcloud_user - Setup a Nextcloud user + + +DESCRIPTION +----------- +It manages a single Nextcloud user given by the object id or parameter `--user`. +This type can create and manage most properties of the Nextcloud user. If you +only want to setup the user, but want that the user will take full control over +all settings (so cdist will not touch the user anymore), use the parameter +`--only-setup` or `--keep-*` for special parameters. + + +REQUIRED PARAMETERS +------------------- +cloud + The absolute path of the Nextcloud installation. + + +OPTIONAL PARAMETERS +------------------- +state + The state the user should be in. Can be the following: + + present *(default)* + The user exists. + + enabled + The user exists and is enabled. + + disabled + The user exists and is disabled. + + absent + The user does not exist. + +user + Takes the uid of the Nextcloud user which will be handled by this type. If + this is not set, the object id will be taken instead. + +www-user + The unix user which will be used to execute Nextcloud related stuff. You + should always use the same user for all Nextcloud interactions, for the + webserver and cli execution. As default, `www-data` will be used. + +displayname + The display name the user should have. As the display name can not be unset + or set to empty, this type will ignore the display name if this parameter + is not set. Setting the parameter to an empty string leads to an error from + the Nextcloud side. + +email + The email address of the Nextcloud user. Will be unset if no parameter + given. + +password + The password of the Nextcloud user. If the password not match, the new + password will be set to the user. If no password is given, it will not + touch the current password. **A password is required for the user setup!** + If you do not want to modify the user password, set a password via this + parameter and set the parameter `--keep-password`. + + Note that Nextcloud will check for the security of passwords. The type + will abort if Nextcloud refuses that password! + +quota + The quota the Nextcloud user have to store it data. Defaults to `default`. + Following values are accepted by Nextcloud: + + default + Uses the quota set as default in Nextcloud. + + none + No quota limit set; unlimited. + + $size + The quota that should be used. Same values as set over the user + interface. First the number, then a space and then the unit like `GB`. + +group + Multiple group names which the Nextcloud user belongs to. If not set, the + user will be removed from every group he is in. + + +BOOLEAN PARAMETERS +------------------ +only-setup + Only provisioning the user if he does not exist. Do not touch the user if + he already exists (except to enforce the given state). + +keep-displayname + Do not touch the display name of the user if he is already set up. This + will avoid to delete the user-set value because it does not match with the + predefined state. If the parameter `--displayname` is set despite of this + parameter, it will only be used in the user setup if he does not already + exist. + +keep-email + Do not touch the email attributes of the user if he is already set up. This + will avoid to delete the user-set value because it does not match with the + predefined state. If the parameter `--email` is set despite of this + parameter, it will only be used in the user setup if he does not already + exist. + +keep-password + Do not touch the password if the user is already set up. This will avoid to + delete user-set passwords because they do not match with the predefined + state. If the parameter `--password` is set despite of this parameter, it + will only be used in the user setup if he does not already exists. + +keep-quota + Do not touch the user quota if he is already set up. This will avoid to + delete the configuration set by an administrator. If the parameter `--quota` + is set despite of this parameter, it will only be used in the user setup if + he does not already exist. + +keep-groups + Do not touch the user groups if the user is already set up. This will avoid + to delete group assosiactions not defined via cdist. If the parameter + `--group` is set despite of this parameter, it will only be used in the user + setup if he does not already exists. + + +MESSAGES +-------- +created + The user as created. + +enabled + The user already exists and was enabled. + +disabled + The user already exists and was disabled. + +removed + The user was removed. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Nextcloud base installation + __nextcloud /var/www/html/cloud $args + + # setups an user, but do not touch it after it was created + require="__nextcloud/var/www/html/cloud" __nextcloud_user foo \ + --cloud /var/www/html/cloud/ \ + --displayname "Big Fooo" \ + --email "foo@bar.tld" \ + --password "do-not-use-this-password" \ + --group "team_a" --group "xxxx" \ + --quota "2 GB" + --only-setup + + # manages an admin user fully controlled by cdist + require="__nextcloud/var/www/html/cloud" __nextcloud_user bar \ + --cloud /var/www/html/cloud/ \ + --displayname "Bar" \ + --email "bar@bar.tld" \ + --password "nope_insecure" \ + --group "admin" + + # disables an user + require="__nextcloud/var/www/html/cloud" __nextcloud_user bb \ + --state disabled \ + --cloud /var/www/html/cloud/ \ + --displayname "byebye" \ + --password "do_not_copy" \ + --keep-email --keep-password --keep-quota --keep-groups + + # removes an user + require="__nextcloud/var/www/html/cloud" __nextcloud_user foobar \ + --state absent \ + --cloud /var/www/html/cloud/ + + + # Different cloud + __nextcloud /var/www/html/nextcloud $args + # but same user name + require="__nextcloud/var/www/html/nextcloud" __nextcloud_user next_foobar \ + --cloud /var/www/html/nextcloud/ --user foobar + + +NOTES +----- +This type may be extended by more user settings. If you think some +configuration is missing, you are welcome to contribute! + +Sometimes, this type uses custom php code to hack into Nextcloud to gather some +information not possible to get via the `occ` command or even set a value. + + +SEE ALSO +-------- +:strong:`cdist-type__nextcloud`\ (7) +:strong:`cdist-type__nextcloud_app`\ (7) + + +AUTHORS +------- +Matthias Stecher + + +COPYING +------- +Copyright \(C) 2020 Matthias Stecher. +You can redistribute it and/or modify it under the terms of the GNU +General Public License as published by the Free Software Foundation, +either version 3 of the License, or (at your option) any later version. diff --git a/type/__nextcloud_user/parameter/boolean b/type/__nextcloud_user/parameter/boolean new file mode 100644 index 0000000..cf0a40a --- /dev/null +++ b/type/__nextcloud_user/parameter/boolean @@ -0,0 +1,6 @@ +only-setup +keep-displayname +keep-email +keep-password +keep-quota +keep-groups diff --git a/type/__nextcloud_user/parameter/default/quota b/type/__nextcloud_user/parameter/default/quota new file mode 100644 index 0000000..4ad96d5 --- /dev/null +++ b/type/__nextcloud_user/parameter/default/quota @@ -0,0 +1 @@ +default diff --git a/type/__nextcloud_user/parameter/default/state b/type/__nextcloud_user/parameter/default/state new file mode 100644 index 0000000..e7f6134 --- /dev/null +++ b/type/__nextcloud_user/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/type/__nextcloud_user/parameter/default/www-user b/type/__nextcloud_user/parameter/default/www-user new file mode 100644 index 0000000..5bbad18 --- /dev/null +++ b/type/__nextcloud_user/parameter/default/www-user @@ -0,0 +1 @@ +www-data diff --git a/type/__nextcloud_user/parameter/optional b/type/__nextcloud_user/parameter/optional new file mode 100644 index 0000000..aaf31d0 --- /dev/null +++ b/type/__nextcloud_user/parameter/optional @@ -0,0 +1,7 @@ +user +www-user +state +displayname +email +password +quota diff --git a/type/__nextcloud_user/parameter/optional_multiple b/type/__nextcloud_user/parameter/optional_multiple new file mode 100644 index 0000000..3a60cce --- /dev/null +++ b/type/__nextcloud_user/parameter/optional_multiple @@ -0,0 +1 @@ +group diff --git a/type/__nextcloud_user/parameter/required b/type/__nextcloud_user/parameter/required new file mode 100644 index 0000000..c3de202 --- /dev/null +++ b/type/__nextcloud_user/parameter/required @@ -0,0 +1 @@ +cloud diff --git a/type/__nginx/man.rst b/type/__nginx/man.rst new file mode 100644 index 0000000..c1827c0 --- /dev/null +++ b/type/__nginx/man.rst @@ -0,0 +1,67 @@ +cdist-type__nginx(7) +=================================== + +NAME +---- +cdist-type__nginx - Serve web content with NGINX + + +DESCRIPTION +----------- +Leverages `__nginx_vhost` to serve web content. + +REQUIRED PARAMETERS +------------------- +domain + Domain name to be served. + +OPTIONAL PARAMETERS +------------------- +config + Custom NGINX logic, templated within a standard `server` section with + `server_name` and TLS parameters set. Defaults to simple static hosting. + +altdomains + Alternative domain names for this vhost and related TLS certificate. + +uacme-hookscript + Custom hook passed to the __uacme_obtain type: useful to integrate the + dns-01 challenge with third-party DNS providers. + +acme-url + ACMEv2 server directory object URL. Lets'Encrypt is used by default. + +acme-eab-credentials + Specify RFC8555 External Account Binding credentials according to + https://tools.ietf.org/html/rfc8555#section-7.3.4, in order to associate a new + ACME account with an existing account in a non-ACME system such as a CA + customer database. KEYID must be an ASCII string. KEY must be + base64url-encoded. + +EXAMPLES +-------- + +.. code-block:: sh + + # TLS-enabled vhost serving static files in $WEBROOT/domain.tld (OS-specific, + # usually `/var/www` on GNU/Linux systemd). + __nginx domain.tld + + # TLS-enabled vhost with custom configuration. + __nginx files.domain.tld \ + --config - <<- EOF + root /var/www/files.domain.tld/; + autoindex on; + EOF + +AUTHORS +------- +Timothée Floure +Joachim Desroches + +COPYING +------- +Copyright \(C) 2020 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__nginx/manifest b/type/__nginx/manifest new file mode 100644 index 0000000..cdd483a --- /dev/null +++ b/type/__nginx/manifest @@ -0,0 +1,96 @@ +#!/bin/sh + +os="$(cat "${__global:?}"/explorer/os)" +case "$os" in + alpine) + nginx_user=nginx + nginx_certdir=/etc/nginx/ssl + ;; + debian|ubuntu) + nginx_user=www-data + nginx_certdir=/etc/nginx/ssl + ;; + *) + echo "This type does not support $os yet. Aborting." >&2; + exit 1; + ;; +esac + +if [ -f "${__object:?}/parameter/domain" ]; +then + domain="$(cat "${__object:?}/parameter/domain")" +else + domain="${__object_id:?}" +fi + +altdomains= +if [ -f "${__object:?}/parameter/altdomains" ]; +then + altdomains="$(cat "${__object:?}/parameter/altdomains")" +fi + +set_custom_uacme_hookscript= +if [ -f "${__object:?}/parameter/uacme-hookscript" ]; +then + uacme_hookscript="$(cat "${__object:?}/parameter/uacme-hookscript")" + set_custom_uacme_hookscript="--hookscript $uacme_hookscript" +fi + +set_custom_acme_url= +if [ -f "${__object:?}/parameter/acme-url" ]; +then + custom_acme_url=$(cat "${__object:?}/parameter/acme-url") + set_custom_acme_url="--acme-url $custom_acme_url" +fi + +set_acme_eab_credentials= +if [ -f "${__object:?}/parameter/acme-eab-credentials" ]; +then + acme_eab_credentials=$(cat "${__object:?}/parameter/acme-eab-credentials") + set_acme_eab_credentials="--eab-credentials $acme_eab_credentials" +fi + +# Deploy simple HTTP vhost, allowing to serve ACME challenges. +__nginx_vhost "301-to-https-$domain" \ + --domain "$domain" --altdomains "$altdomains" --to-https + +# Obtaining TLS cert. +cert_ownership=$nginx_user +if [ -f "${__object:?}/parameter/force-cert-ownership-to" ]; then + cert_ownership=$(cat "${__object:?}/parameter/force-cert-ownership-to") +fi + +# shellcheck disable=SC2086 +__uacme_account \ + $set_custom_acme_url \ + $set_acme_eab_credentials \ + +# shellcheck disable=SC2086 +require="__nginx_vhost/301-to-https-$domain __uacme_account" \ + __uacme_obtain "$domain" \ + --altdomains "$altdomains" \ + $set_custom_uacme_hookscript \ + $set_custom_acme_url \ + $set_acme_eab_credentials \ + --owner "$cert_ownership" \ + --install-key-to "$nginx_certdir/$domain/privkey.pem" \ + --install-cert-to "/$nginx_certdir/$domain/fullchain.pem" \ + --renew-hook "service nginx reload" + +# Deploy HTTPS nginx vhost. +if [ -f "${__object:?}/parameter/config" ]; then + if [ "$(cat "${__object:?}/parameter/config")" = "-" ]; then + nginx_logic="${__object:?}/stdin" + else + nginx_logic="${__object:?}/parameter/config" + fi + + mkdir -p "${__object:?}/files" + cat "$nginx_logic" > "${__object:?}/files/config" + + require="__uacme_obtain/$domain" __nginx_vhost "$domain" \ + --altdomains "$altdomains" --config "${__object:?}/files/config" +else + require="__uacme_obtain/$domain" __nginx_vhost "$domain" \ + --altdomains "$altdomains" +fi diff --git a/type/__nginx/parameter/default/http-port b/type/__nginx/parameter/default/http-port new file mode 100644 index 0000000..d15a2cc --- /dev/null +++ b/type/__nginx/parameter/default/http-port @@ -0,0 +1 @@ +80 diff --git a/type/__nginx/parameter/default/https-port b/type/__nginx/parameter/default/https-port new file mode 100644 index 0000000..6a13cf6 --- /dev/null +++ b/type/__nginx/parameter/default/https-port @@ -0,0 +1 @@ +443 diff --git a/type/__nginx/parameter/optional b/type/__nginx/parameter/optional new file mode 100644 index 0000000..8d6fae6 --- /dev/null +++ b/type/__nginx/parameter/optional @@ -0,0 +1,7 @@ +config +domain +altdomains +uacme-hookscript +acme-url +acme-eab-credentials +force-cert-ownership-to diff --git a/type/__nginx_vhost/files/301-to-https b/type/__nginx_vhost/files/301-to-https new file mode 100644 index 0000000..2675732 --- /dev/null +++ b/type/__nginx_vhost/files/301-to-https @@ -0,0 +1,4 @@ +# Redirect request to this page in HTTPS. +location / { + return 301 https://$host$request_uri; +} diff --git a/type/__nginx_vhost/files/generic.conf.sh b/type/__nginx_vhost/files/generic.conf.sh new file mode 100755 index 0000000..13e36aa --- /dev/null +++ b/type/__nginx_vhost/files/generic.conf.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# Template for static NGINX hosting. + +echo 'server {' + +# Listen +cat <<- EOF + listen ${LPORT:?} $TLS; + listen [::]:${LPORT:?} $TLS; +EOF + +# Name +echo "server_name ${DOMAIN:?} $ALTDOMAINS;" + +# ACME challenges. +cat << EOF +location /.well-known/acme-challenge/ { + alias ${ACME_CHALLENGE_DIR:?}; +} +EOF + +if [ -n "$TLS" ]; +then + if [ -n "$HSTS" ]; + then + echo 'include snippets/hsts;' + fi + + cat <<- EOF + ssl_certificate ${NGINX_CERTDIR:?}/${DOMAIN:?}/fullchain.pem; + ssl_certificate_key ${NGINX_CERTDIR:?}/${DOMAIN:?}/privkey.pem; + EOF +fi + +echo "${NGINX_LOGIC:?}" + +echo '}' diff --git a/type/__nginx_vhost/files/hsts b/type/__nginx_vhost/files/hsts new file mode 100644 index 0000000..7e4a854 --- /dev/null +++ b/type/__nginx_vhost/files/hsts @@ -0,0 +1 @@ +add_header Strict-Transport-Security "max-age=31536000" always; diff --git a/type/__nginx_vhost/files/index.html b/type/__nginx_vhost/files/index.html new file mode 100644 index 0000000..bcadf4d --- /dev/null +++ b/type/__nginx_vhost/files/index.html @@ -0,0 +1,12 @@ + + + + + + cdist configured! + + + You have successfully configured a vhost with + cdist. You can now upload content! + + diff --git a/type/__nginx_vhost/files/static.conf.sh b/type/__nginx_vhost/files/static.conf.sh new file mode 100755 index 0000000..363f228 --- /dev/null +++ b/type/__nginx_vhost/files/static.conf.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# Template for static NGINX hosting. + +NGINX_LOGIC="$(cat << EOF + location / { + root ${NGINX_WEBROOT:?}/${DOMAIN:?}; + index index.html; + } +EOF +)" +export NGINX_LOGIC + +"${__type:?}/files/generic.conf.sh" diff --git a/type/__nginx_vhost/files/to-https.conf.sh b/type/__nginx_vhost/files/to-https.conf.sh new file mode 100755 index 0000000..77dd45b --- /dev/null +++ b/type/__nginx_vhost/files/to-https.conf.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# Template for HTTPS redirection. + +echo 'server {' + +# Listen +cat <<- EOF + listen ${LPORT:?}; + listen [::]:${LPORT:?}; +EOF + +# Name +echo "server_name ${DOMAIN:?} $ALTDOMAINS;" + +# ACME challenges. +cat << EOF +location /.well-known/acme-challenge/ { + alias ${ACME_CHALLENGE_DIR:?}; +} +EOF + +# HTTPS redirection. +echo 'include snippets/301-to-https;' + +echo '}' diff --git a/type/__nginx_vhost/gencode-remote b/type/__nginx_vhost/gencode-remote new file mode 100644 index 0000000..dd6539d --- /dev/null +++ b/type/__nginx_vhost/gencode-remote @@ -0,0 +1,35 @@ +#!/bin/sh + +os="$(cat "${__global:?}"/explorer/os)" +init=$(cat "$__global/explorer/init") +nginx_confdir="/etc/nginx" + +# The nginx service is not automatically started on alpine. +if [ "$os" = "alpine" ]; then + echo "service nginx --ifstopped start" +fi + +if grep -qE "^__file$nginx_confdir" "${__messages_in:?}"; then + case "$init" in + systemd) + reload_hook="systemctl reload-or-restart nginx" + ;; + busybox-init+openrc) + reload_hook="service nginx reload" + ;; + *) + echo "Unknown init $init." >&2 + exit 1 + ;; + esac + + cat <<- EOF + if nginx -t; then + $reload_hook + else + echo "NGINX configuration is invalid. Exiting." >2& + nginx -t >2& + exit 1 + fi + EOF +fi diff --git a/type/__nginx_vhost/man.rst b/type/__nginx_vhost/man.rst new file mode 100644 index 0000000..c078b10 --- /dev/null +++ b/type/__nginx_vhost/man.rst @@ -0,0 +1,82 @@ +cdist-type__nginx_vhost(7) +=================================== + +NAME +---- +cdist-type__nginx_vhost - Have nginx serve content for a virtual host + + +DESCRIPTION +----------- +This type setups up nginx with reasonable defaults and creates a vhost to be +served, optionally with TLS certificates obtained from the Let's Encrypt CA +through the ACME HTTP-01 challenge-response mechanism. + +By default, if no rules are specified, then the vhost will serve as-is the +contents of the `WEBROOT/foo.com` directory, where WEBROOT is +determined depending on the OS, adhering as close to `hier(7)` as possible. + +NGINX expects files in the vhost to be served to be at least readable by the +`USER` group, that it creates if it does not exist. It is recommended to have +the user owning the files to be someone else, and the files beeing +group-readable but not writeable. + +Finally, if TLS is not disabled, then this type makes nginx expect the +fullchain certificate and the private key in +`CERTDIR/domain/{fullchain,privkey}.pem`. + ++------------------+---------+-------------------+-----------------------------+ +| Operating System | USER | WEBROOT | CERTDIR | ++==================+=========+===================+=============================+ +| Alpine Linux | `nginx` | `/srv/www/` | `/etc/nginx/ssl/` | ++------------------+---------+-------------------+-----------------------------+ +| Arch Linux | `www` | `/srv/www/` | `/etc/nginx/ssl/` | ++------------------+---------+-------------------+-----------------------------+ + +OPTIONAL PARAMETERS +------------------- + +config + A custom configuration file for the vhost, inserted in a server section + populated with `server_name` and TLS parameters unless `--standalone-config` + is specified. Can be specified either as a file path, or if the value of this + flag is '-', then the configuration is read from stdin. + +domain + The domain this server will respond to. If this is omitted, then the + `__object_id` is used. + +lport + The port to which we listen. If this is omitted, the defaults of `80` for + HTTP and `443` for HTTPS are used. + +altdomains + Alternative domain names for this vhost. + +BOOLEAN PARAMETERS +------------------ + +no-hsts + Do not use HSTS pinning. + +no-tls + Do not serve over HTTPS. + +to-https + Ignore --config flag and redirect to HTTPS. Implies --no-tls. + +standalone-config + Use as-in the vhost configuration (= do not wrap in generic server section) + the content of the `config` parameter. + +AUTHORS +------- +Joachim Desroches +Timothée Floure + +COPYING +------- +Copyright \(C) 2020 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__nginx_vhost/manifest b/type/__nginx_vhost/manifest new file mode 100644 index 0000000..8b010f8 --- /dev/null +++ b/type/__nginx_vhost/manifest @@ -0,0 +1,164 @@ +#!/bin/sh +# +# 2020 Joachim Desroches +# 2021 Timothée Floure +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# +# Create NGINX vhosts + +os="$(cat "${__global:?}"/explorer/os)" +mkdir -p "${__object:?}/files" + +case "$os" in + alpine) + __package nginx + + nginx_confdir="/etc/nginx" + install_reqs="__package/nginx" + + require="$install_reqs" __start_on_boot nginx + + export NGINX_SITEDIR="$nginx_confdir/http.d" + export NGINX_CERTDIR="$nginx_confdir/ssl" + export NGINX_SNIPPETSDIR="$nginx_confdir/snippets" + export NGINX_WEBROOT="/var/www" + export ACME_CHALLENGE_DIR="$NGINX_WEBROOT/.well-known/acme-challenge/" + ;; + debian|ubuntu) + __package nginx + + nginx_confdir="/etc/nginx" + install_reqs="__package/nginx" + + export NGINX_SITEDIR="$nginx_confdir/sites-enabled" + export NGINX_CERTDIR="$nginx_confdir/ssl" + export NGINX_SNIPPETSDIR="$nginx_confdir/snippets" + export NGINX_WEBROOT="/var/www" + export ACME_CHALLENGE_DIR="$NGINX_WEBROOT/.well-known/acme-challenge/" + ;; + *) + echo "This type does not support $os yet. Aborting." >&2; + exit 1; +esac + +# Domain +if [ -f "${__object:?}/parameter/domain" ]; +then + DOMAIN="$(cat "${__object:?}/parameter/domain")" +else + DOMAIN="${__object_id:?}" +fi +export DOMAIN + +ALTDOMAINS= +if [ -f "${__object:?}/parameter/altdomains" ]; +then + ALTDOMAINS="$(cat "${__object:?}/parameter/altdomains")" +fi +export ALTDOMAINS + +# Use TLS ? +if [ -f "${__object:?}/parameter/no-tls" ]; +then + TLS= + echo "WARNING: you have disabled TLS for vhost $DOMAIN" >&2 +else + TLS=ssl +fi +export TLS + +# Use HSTS ? +if [ -f "${__object:?}/parameter/no-hsts" ]; +then + HSTS= +else + HSTS=true +fi +export HSTS + +# Redirect to HTTPS ? +if [ -f "${__object:?}/parameter/to-https" ]; +then + TO_HTTPS=true +else + TO_HTTPS= +fi +export HSTS + +# Port to listen on +if [ -f "${__object:?}/parameter/lport" ]; +then + LPORT="$(cat "${__object:?}/parameter/lport")" +else + if [ -n "$TLS" ] && [ -z "$TO_HTTPS" ]; + then + LPORT=443 + else + LPORT=80 + fi +fi +export LPORT + +# Server definition +if [ -n "$TO_HTTPS" ]; +then + # Ignore configuration, simply serve ACME challenge and redirect to HTTPS. + "${__type:?}/files/to-https.conf.sh" > "${__object:?}/files/vhost.conf" + vhost_conf="${__object:?}/files/vhost.conf" +elif [ -f "${__object:?}/parameter/config" ]; +then + # Extract nginx config from type parameter. + if [ "$(cat "${__object:?}/parameter/config")" = "-" ]; + then + vhost_partial="${__object:?}/stdin" + else + vhost_partial=$(cat "${__object:?}/parameter/config") + fi + + # Either use config as-in or template it in generic vhost structure. + if [ -f "${__object:?}/parameter/standalone-config" ]; then + vhost_conf=$vhost_partial + else + NGINX_LOGIC=$(cat "$vhost_partial") "${__type:?}/files/generic.conf.sh" \ + > "${__object:?}/files/vhost.conf" + + vhost_conf="${__object:?}/files/vhost.conf" + fi +else + # Default to simple static configuration. + "${__type:?}/files/static.conf.sh" > "${__object:?}/files/vhost.conf" + vhost_conf="${__object:?}/files/vhost.conf" + + require="$install_reqs" __directory "$NGINX_WEBROOT/$DOMAIN" + require="__directory$NGINX_WEBROOT/$DOMAIN" \ + __file "$NGINX_WEBROOT/$DOMAIN/index.html" --state exists \ + --source "${__type:?}/files/index.html" \ + --mode 0644 +fi + +# Install snippets. +require="$install_reqs" __directory "$NGINX_SNIPPETSDIR" +for snippet in hsts 301-to-https; do + require="__directory/$NGINX_SNIPPETSDIR" __file \ + "$NGINX_SNIPPETSDIR/$snippet" --source "${__type:?}/files/$snippet" +done + +# Install vhost. +require="$install_reqs" __directory "$NGINX_SITEDIR" +require="__directory/$NGINX_SITEDIR" __file "$NGINX_SITEDIR/$__object_id.conf" \ + --source "$vhost_conf" \ + --mode 0644 diff --git a/type/__nginx_vhost/parameter/boolean b/type/__nginx_vhost/parameter/boolean new file mode 100644 index 0000000..aa06036 --- /dev/null +++ b/type/__nginx_vhost/parameter/boolean @@ -0,0 +1,4 @@ +no-tls +no-hsts +to-https +standalone-config diff --git a/type/__nginx_vhost/parameter/default/index b/type/__nginx_vhost/parameter/default/index new file mode 100644 index 0000000..d5b7a40 --- /dev/null +++ b/type/__nginx_vhost/parameter/default/index @@ -0,0 +1 @@ +index.html index.htm diff --git a/type/__nginx_vhost/parameter/optional b/type/__nginx_vhost/parameter/optional new file mode 100644 index 0000000..9c47616 --- /dev/null +++ b/type/__nginx_vhost/parameter/optional @@ -0,0 +1,4 @@ +domain +config +altdomains +lport diff --git a/type/__opendkim/files/opendkim.conf.sh b/type/__opendkim/files/opendkim.conf.sh new file mode 100755 index 0000000..468b262 --- /dev/null +++ b/type/__opendkim/files/opendkim.conf.sh @@ -0,0 +1,65 @@ +#!/bin/sh -e +# Generate an opendkim.conf(5) file for opendkim(8). + +echo "# Managed remotely, manual changes will be lost." + +# Optional chdir(2) +if [ "$BASEDIR" ]; +then + printf "BaseDirectory %s\n" "$BASEDIR" +fi + +# Optional canonicalization settings +if [ "$CANON" ]; +then + case "$CANON" in + "simple/simple") + : + ;; + "simple/relaxed") + : + ;; + "relaxed/simple") + : + ;; + "relaxed/relaxed") + : + ;; + *) + echo "Invalid Canonicalization setting!" >&2 + exit 1 + ;; + esac + printf "Canonicalization %s\n" "$CANON" +fi + +# Key and Domain tables +echo "KeyTable ${CFG_DIR}/KeyTable" +echo "SigningTable ${CFG_DIR}/SigningTable" + +# Required socket to listen on +printf "Socket %s\n" "${SOCKET:?}" + +# Optional subdomain signing settings +if [ "$SUBDOMAINS" ]; +then + printf "SubDomains %s\n" "$SUBDOMAINS" +fi + +# Optional request logging to syslog +if [ "$SYSLOG" ]; +then + echo "Syslog yes" +fi + +# Optional UMask specification +if [ "$UMASK" ]; +then + printf "UMask %s\n" "$UMASK" +fi + +# Optional UserID to change to +if [ "$USERID" ]; +then + printf "UserID %s\n" "$USERID" +fi diff --git a/type/__opendkim/man.rst b/type/__opendkim/man.rst new file mode 100644 index 0000000..996f16d --- /dev/null +++ b/type/__opendkim/man.rst @@ -0,0 +1,102 @@ +cdist-type__opendkim(7) +======================= + +NAME +---- +cdist-type__opendkim - Configure an instance of OpenDKIM + + +DESCRIPTION +----------- +OpenDKIM is a DKIM signing and verifying filter for MTAs. This type enables the +installation and basic configuration of an instance of OpenDKIM. + +Note that this type does not generate or ensure that a key is present: use +`cdist-type__opendkim-genkey(7)` for that. + +Note that this type is currently only implemented for Alpine Linux and FreeBSD. +Please contribute an implementation if you can. + + +REQUIRED PARAMETERS +------------------- +socket + A string specifying a socket to listen on for communication with the MTA. See + `opendkim.conf(5)` for details on the syntax. + + +OPTIONAL PARAMETERS +------------------- +basedir + A directory to `chdir(2)` to before beginning operations. + +canonicalization + Directives for message canonicalization. See `opendkim.conf(5)` for details + on the syntax. + +subdomains + Explicitely control whether subdomains should be signed as well. Expects a + string containing 'Y', 'N', 'y', 'n', 'yes' or 'no'. + +umask + Set the umask for the socket and PID file. + +custom-config + The string following this parameter is appended as-is in the configuration, to + enable more complex configurations. + + +BOOLEAN PARAMETERS +------------------ +syslog + Log to syslog. + + +DEPRECATED PARAMETERS +--------------------- +userid + Change the user the opendkim program is to run as. + By default, Alpine Linux's OpenRC service will set this to `opendkim` on the + command-line and FreeBSD's rc will set it to `mailnull`. + + +EXAMPLES +-------- + +.. code-block:: sh + + __opendkim \ + --socket inet:8891@localhost \ + --basedir /var/lib/opendkim \ + --canonicalization relaxed/simple \ + --subdomains no \ + --umask 002 \ + --syslog \ + --custom-config "Mode v" + + require='__opendkim' \ + __opendkim_genkey mykey \ + --domain example.com \ + --selector default \ + --sigkey example.com + + +SEE ALSO +-------- +`cdist-type__opendkim-genkey(7)` +`opendkim(8)` +`opendkim.conf(5)` + + +AUTHORS +------- +Joachim Desroches +Evilham + + +COPYING +------- +Copyright \(C) 2022 Joachim Desroches, Evilham. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__opendkim/manifest b/type/__opendkim/manifest new file mode 100755 index 0000000..28dd808 --- /dev/null +++ b/type/__opendkim/manifest @@ -0,0 +1,116 @@ +#!/bin/sh -e +# +# 2021 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +os=$(cat "${__global:?}/explorer/os") + +CFG_DIR="/etc/opendkim" +service="opendkim" +case "$os" in +'alpine') + : + ;; +'freebsd') + CFG_DIR="/usr/local/etc/mail" + service="milter-opendkim" + start_service="milteropendkim" + ;; +*) + printf "__opendkim does not yet support %s.\n" "$os" >&2 + printf "Please contribute an implementation if you can.\n" >&2 + exit 1 + ;; +esac +export CFG_DIR + +__package opendkim + +# Required parameters +SOCKET="$(cat "${__object:?}/parameter/socket")" +export SOCKET + +# Optional parameters +if [ -f "${__object:?}/parameter/basedir" ]; then + BASEDIR="$(cat "${__object:?}/parameter/basedir")" + export BASEDIR +fi + +if [ -f "${__object:?}/parameter/canonicalization" ]; then + CANON="$(cat "${__object:?}/parameter/canonicalization")" + export CANON +fi + +if [ -f "${__object:?}/parameter/subdomains" ]; then + SUBDOMAINS="$(cat "${__object:?}/parameter/subdomains")" + export SUBDOMAINS +fi + +if [ -f "${__object:?}/parameter/umask" ]; then + UMASK="$(cat "${__object:?}/parameter/umask")" + export UMASK +fi + +if [ -f "${__object:?}/parameter/userid" ]; then + USERID="$(cat "${__object:?}/parameter/userid")" + export USERID +fi + +# Boolean parameters +[ -f "${__object:?}/parameter/syslog" ] && export SYSLOG=yes + +# Generate and deploy configuration file. +source_file="${__object:?}/files/opendkim.conf" +target_file="${CFG_DIR}/opendkim.conf" + +mkdir -p "${__object:?}/files" + +"${__type:?}/files/opendkim.conf.sh" >"$source_file" + +# Add user custom config +if [ -f "${__object:?}/parameter/custom-config" ]; then + echo "# Custom user config" >>"$source_file" + cat "${__object:?}/parameter/custom-config" >>"$source_file" +fi + +require="__package/opendkim" __file "$target_file" \ + --source "$source_file" --mode 0644 + +# Due to the way rc.conf works on *BSD, we find ourselves in the awkward +# situation, where a service's name can contain a '-' symbol, but the +# rc.conf setting to enable a service at boot cannot. +# Unless start_service has been defined before, these two match. +require="__package/opendkim" __start_on_boot "${start_service:-${service}}" + +# Ensure Key and Signing tables exist and have proper permissions +key_table="${CFG_DIR}/KeyTable" +signing_table="${CFG_DIR}/SigningTable" + +require="__package/opendkim" \ + __file "${key_table}" \ + --mode 444 + +require="__package/opendkim" \ + __file "${signing_table}" \ + --mode 444 + +require="__file${target_file} __file${key_table} + __file${signing_table} __start_on_boot/${start_service:-${service}}" \ + __check_messages opendkim \ + --pattern "^__file${target_file}" \ + --execute "service ${service} restart" diff --git a/type/__opendkim/parameter/boolean b/type/__opendkim/parameter/boolean new file mode 100644 index 0000000..24e5b1b --- /dev/null +++ b/type/__opendkim/parameter/boolean @@ -0,0 +1 @@ +syslog diff --git a/type/__opendkim/parameter/deprecated/userid b/type/__opendkim/parameter/deprecated/userid new file mode 100644 index 0000000..1815a0a --- /dev/null +++ b/type/__opendkim/parameter/deprecated/userid @@ -0,0 +1,2 @@ +This can cause inconsistencies with permissions and will stop being supported. +If you still need this, you can use --custom-config 'UserId $USERID'. diff --git a/type/__opendkim/parameter/optional b/type/__opendkim/parameter/optional new file mode 100644 index 0000000..af59609 --- /dev/null +++ b/type/__opendkim/parameter/optional @@ -0,0 +1,6 @@ +basedir +canonicalization +subdomains +umask +userid +custom-config diff --git a/type/__opendkim/parameter/required b/type/__opendkim/parameter/required new file mode 100644 index 0000000..3cdd2fd --- /dev/null +++ b/type/__opendkim/parameter/required @@ -0,0 +1 @@ +socket diff --git a/type/__opendkim/singleton b/type/__opendkim/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__opendkim_genkey/explorer/key-state b/type/__opendkim_genkey/explorer/key-state new file mode 100755 index 0000000..75998f9 --- /dev/null +++ b/type/__opendkim_genkey/explorer/key-state @@ -0,0 +1,32 @@ +#!/bin/sh -e +DIRECTORY="/var/db/dkim/" +if [ -f "${__object:?}/parameter/directory" ]; +then + # Be forgiving about a lack of trailing slash + DIRECTORY="$(sed -E 's!([^/])$!\1/!' < "${__object:?}/parameter/directory")" +fi + + +KEY_ID="$(echo "${__object_id:?)}" | tr '/' '_')" +DEFAULT_PATH="${DIRECTORY:?}${KEY_ID:?}.private" +if [ -s "${DEFAULT_PATH}" ]; then + # This is the main location for the key + FOUND_PATH="${DEFAULT_PATH}" +else + # This is a backwards-compatible location for the key + # Keys generated post March 2022 should not land here + if [ -f "${__object:?}/parameter/selector" ]; then + SELECTOR="$(cat "${__object:?}/parameter/selector")" + if [ -s "${DIRECTORY}${SELECTOR:?}.private" ]; then + FOUND_PATH="${DIRECTORY}${SELECTOR:?}.private" + fi + fi +fi + +if [ -n "${FOUND_PATH}" ]; then + printf "present\t%s" "${FOUND_PATH}" +else + # We didn't find the key + # We pass the default path here, to easen logic in the rest of the type + printf "absent\t%s" "${DEFAULT_PATH}" +fi diff --git a/type/__opendkim_genkey/gencode-remote b/type/__opendkim_genkey/gencode-remote new file mode 100755 index 0000000..d2bea50 --- /dev/null +++ b/type/__opendkim_genkey/gencode-remote @@ -0,0 +1,65 @@ +#!/bin/sh -e +# +# 2021 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# Required parameters +DOMAIN="$(cat "${__object:?}/domain")" +SELECTOR="$(cat "${__object:?}/selector")" + +# Optional parameters +BITS= +if [ -f "${__object:?}/parameter/bits" ]; then + BITS="-b $(cat "${__object:?}/parameter/bits")" +fi + +# Boolean parameters +SUBDOMAINS= +if [ -f "${__object:?}/parameter/no-subdomains" ]; then + SUBDOMAINS='--nosubdomains' +fi + +RESTRICTED='--restrict' +if [ -f "${__object:?}/parameters/unrestricted" ]; then + RESTRICTED= +fi + +user="$(cat "${__object:?}/user")" +group="$(cat "${__object:?}/group")" + +KEY_STATE="$(cut -f 1 "${__object:?}/explorer/key-state")" +KEY_LOCATION="$(cut -f 2- "${__object:?}/explorer/key-state")" + +if [ "${KEY_STATE:?}" = "absent" ]; then + # opendkim-genkey(8) does not allow specifying the file name. + # To err on the safe side (and avoid potentially killing other keys) + # we operate on a temporary directory first, then move the resulting key + cat <<-EOF + tmp_dir="\$(mktemp -d cdist-dkim.XXXXXXXXXXX)" + opendkim-genkey $BITS --domain=${DOMAIN:?} --directory=\${tmp_dir:?} $RESTRICTED --selector=${SELECTOR:?} $SUBDOMAINS + # Relocate and ensure permissions + mv "\${tmp_dir:?}/${SELECTOR:?}.private" '${KEY_LOCATION:?}' + chown ${user}:${group} '${KEY_LOCATION}' + chmod 0600 '${KEY_LOCATION}' + # This is usually generated, if it weren't we do not want to fail + mv "\${tmp_dir:?}/${SELECTOR:?}.txt" '${KEY_LOCATION%.private}.txt' || true + chown ${user}:${group} '${KEY_LOCATION%.private}.txt' || true + # Cleanup after ourselves + rmdir "\${tmp_dir:?}" || true + EOF +fi diff --git a/type/__opendkim_genkey/man.rst b/type/__opendkim_genkey/man.rst new file mode 100644 index 0000000..0d52ca3 --- /dev/null +++ b/type/__opendkim_genkey/man.rst @@ -0,0 +1,137 @@ +cdist-type__opendkim_genkey(7) +============================== + +NAME +---- +cdist-type__opendkim_genkey - Generate DKIM keys suitable for OpenDKIM + + +DESCRIPTION +----------- + +This type uses the `opendkim-genkey(8)` to generate signing keys suitable for +usage by `opendkim(8)` to sign outgoing emails. + +It also manages the key, identified by its `$__object_id` in OpenDKIM's +KeyTable and sets its `s=` and `d=` parameters (see: `--selector` and +`--sigdomain` respectively). + +This type will also manage the entries in the OpenDKIM's SigningTable by +associating any given `sigkey` values to this key. + +Take into account that if you use this type without the `--domain` and +`--selector` parameters, the `$__object_id` must be in form `$domain/$selector`. + +Currently, this type is only implemented for Alpine Linux and FreeBSD. +Please contribute an implementation if you can. + +NOTE: the name of the key file under `--directory` will default to +`$__object_id.private`, but if that fails and `--selector` is used, +`SELECTOR.private` will be considered. +Take care when using unrelated keys that might collide this way. +For more information see: +https://code.ungleich.ch/ungleich-public/cdist-contrib/issues/20 + + +OPTIONAL PARAMETERS +------------------- +bits + The size of the generated key, in bits. The default is 1024, the recommended + by the DKIM standard. + +directory + The directory in which to generate the key, `/var/db/dkim/` by default. + +domain + The domain to generate the key for. + If omitted, `--selector` must be omitted as well and `$__object_id` must be + in form: `$domain/$selector`. + +selector + The DKIM selector to generate the key for. + If omitted, `--domain` must be omitted as well and `$__object_id` must be + in form: `$domain/$selector`. + +sigdomain + Specified in the KeyTable, the domain to use in the signature's "d=" value. + Defaults to the specified domain. If `%`, it will be replaced by the apparent + domain of the sender when generating a signature. + Note you probably don't want to set both `--sigdomain` and `--sigkey` to `%`. + See `KeyTable` in `opendkim.conf(5)` for more information. + + +OPTIONAL MULTIPLE PARAMETERS +---------------------------- +sigkey + The key used in the `SigningTable` for this signing key. Defaults to the + specified domain. If `%`, OpenDKIM will replace it with the domain found + in the `From:` header. See `opendkim.conf(5)` for more options. + Note you probably don't want to set both `--sigdomain` and `--sigkey` to `%`. + This can be passed multiple times, resulting in multiple lines in the + SigningTable, which can be used to support signing of subdomains or multiple + domains with the same key; in that case, you probably want to set + `--sigdomain` to `%`, else the domains will not be aligned. + + +BOOLEAN PARAMETERS +------------------ +no-subdomains + Disallows subdomain signing by this key. + +unrestricted + Do not restrict this key to email signing usage. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Setup the OpenDKIM service + __opendkim \ + --socket inet:8891@localhost \ + --basedir /var/lib/opendkim \ + --canonicalization relaxed/simple \ + --subdomains no \ + --umask 002 \ + --syslog + + # Continue only after the service has been set up + export require="__opendkim" + + # Generate a key for 'example.com' with selector 'default' + __opendkim_genkey default \ + --domain example.com \ + --selector default + + # Generate a key for 'foo.com' with selector 'backup' + __opendkim_genkey 'foo.com/backup' + + # Generate a key for 'example.org' with selector 'main' + # that can also sign 'cdi.st' and subdomains of 'example.org' + __opendkim_genkey 'example.org/main' \ + --sigdomain '%' \ + --sigkey 'example.org' \ + --sigkey '.example.org' \ + --sigkey 'cdi.st' + + +SEE ALSO +-------- +`opendkim(8)` +`opendkim-genkey(8)` +`cdist-type__opendkim(7)` + + +AUTHORS +------- +Joachim Desroches +Evilham + + +COPYING +------- +Copyright \(C) 2022 Joachim Desroches, Evilham. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__opendkim_genkey/manifest b/type/__opendkim_genkey/manifest new file mode 100755 index 0000000..58e9b06 --- /dev/null +++ b/type/__opendkim_genkey/manifest @@ -0,0 +1,139 @@ +#!/bin/sh -e +# +# 2021 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + + +os=$(cat "${__global:?}/explorer/os") + +CFG_DIR="/etc/opendkim" +user="opendkim" +group="opendkim" +case "$os" in +'alpine') + : +;; +'freebsd') + CFG_DIR="/usr/local/etc/mail" + user="mailnull" + group="mailnull" +;; +*) + cat <<- EOF >&2 + __opendkim_genkey currently only supports Alpine Linux and FreeBSD. + Please contribute an implementation for $os if you can. + EOF + exit 1 +;; +esac + +# Logic to simplify the type as documented in +# https://code.ungleich.ch/ungleich-public/cdist-contrib/issues/20#issuecomment-14711 +DOMAIN="$(cat "${__object:?}/parameter/domain" 2>/dev/null || true)" +SELECTOR="$(cat "${__object:?}/parameter/selector" 2>/dev/null || true)" +if [ -z "${DOMAIN}${SELECTOR}" ]; then + # Neither SELECTOR nor DOMAIN were passed, try to use __object_id + if echo "${__object_id:?}" | \ + grep -qE '^[^/[:space:]]+/[^/[:space:]]+$'; then + # __object_id matches, let's get the data + DOMAIN="$(echo "${__object_id:?}" | cut -d '/' -f 1)" + SELECTOR="$(echo "${__object_id:?}" | cut -d '/' -f 2)" + else + # It doesn't match the pattern, this is sad + cat <<- EOF >&2 + The arguments --domain and --selector were not used. + So __object_id must match DOMAIN/SELECTOR. + But instead the type got: ${__object_id:?} + EOF + exit 1 + fi +elif [ -z "${DOMAIN}" ] || [ -z "${SELECTOR}" ]; then + # Only one was passed, this is sad :-( + cat <<- EOF >&2 + You must pass either both --selector and --domain or none of them. + If these arguments are absent, __object_id must match: DOMAIN/SELECTOR. + EOF + exit 1 +# else: both were passed +fi + +# Persist data for gencode-remote +printf '%s' "${user:?}" > "${__object:?}/user" +printf '%s' "${group:?}" > "${__object:?}/group" +printf '%s' "${DOMAIN:?}" > "${__object:?}/domain" +printf '%s' "${SELECTOR:?}" > "${__object:?}/selector" + +DIRECTORY="/var/db/dkim/" +if [ -f "${__object:?}/parameter/directory" ]; +then + # Be forgiving about a lack of trailing slash + DIRECTORY="$(sed -E 's!([^/])$!\1/!' < "${__object:?}/parameter/directory")" +fi + +SIGKEY="${DOMAIN:?}" +if [ -f "${__object:?}/parameter/sigkey" ]; +then + SIGKEY="$(cat "${__object:?}/parameter/sigkey")" +fi +SIGDOMAIN="${DOMAIN:?}" +if [ -f "${__object:?}/parameter/sigdomain" ]; +then + SIGDOMAIN="$(cat "${__object:?}/parameter/sigdomain")" +fi + +# Ensure the key-container directory exists with the proper permissions +__directory "${DIRECTORY}" \ + --mode 0750 \ + --owner "${user}" --group "${group}" + +# OS-specific code +case "$os" in +'alpine') + # This is needed for opendkim-genkey + __package opendkim-utils +;; +esac + +key_table="${CFG_DIR}/KeyTable" +signing_table="${CFG_DIR}/SigningTable" + +KEY_STATE="$(cut -f 1 "${__object:?}/explorer/key-state")" +KEY_LOCATION="$(cut -f 2- "${__object:?}/explorer/key-state")" + +__line "__opendkim_genkey/${__object_id:?}" \ + --file "${key_table}" \ + --line "${__object_id:?} ${SIGDOMAIN:?}:${SELECTOR:?}:${KEY_LOCATION:?}" \ + --regex "^${__object_id:?}[[:space:]]" \ + --state 'replace' + +sigtable_block() { + for sigkey in ${SIGKEY:?}; do + echo "${sigkey:?} ${__object_id:?}" + done +} +__block "__opendkim_genkey/${__object_id:?}" \ + --file "${signing_table}" \ + --text "$(sigtable_block)" + +if [ "${KEY_STATE:?}" = "present" ]; then + # Ensure proper permissions for the key file + __file "${KEY_LOCATION}" \ + --owner "${user}" \ + --group "${group}" \ + --mode 0600 +fi diff --git a/type/__opendkim_genkey/parameter/optional b/type/__opendkim_genkey/parameter/optional new file mode 100644 index 0000000..9d9b6d1 --- /dev/null +++ b/type/__opendkim_genkey/parameter/optional @@ -0,0 +1,6 @@ +bits +directory +domain +unrestricted +selector +sigdomain diff --git a/type/__opendkim_genkey/parameter/optional_multiple b/type/__opendkim_genkey/parameter/optional_multiple new file mode 100644 index 0000000..35978a9 --- /dev/null +++ b/type/__opendkim_genkey/parameter/optional_multiple @@ -0,0 +1 @@ +sigkey diff --git a/type/__pass/gencode-local b/type/__pass/gencode-local new file mode 100755 index 0000000..3346707 --- /dev/null +++ b/type/__pass/gencode-local @@ -0,0 +1,77 @@ +#!/bin/sh -e +# +# 2020 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +cat <<- EOF + +# Length of generated password. +LENGTH= + +# Keep password strictly alphanumeric. +NOSYMB= + +# Check pass is installed. +command -v pass >/dev/null 2>&1 || + { + cat <<- EOF >&2 + __pass: this type requires pass installed. + See https://www.passwordstore.org/. + EOFF + exit 1; + } + +# Check for optional length parameter. +if [ -f "${__object:?}/parameter/length" ]; +then + LENGTH="$(cat "${__object:?}/parameter/length")" + export LENGTH +fi + +# Check for optional no symbols parameter. +if [ -f "${__object:?}/parameter/no-symbols" ]; +then + NOSYMB="-n" + export NOSYMB +fi + +# Load required password store location parameter. +PASSWORD_STORE_DIR="$(cat "${__object:?}/parameter/storedir")" +export PASSWORD_STORE_DIR + +# Check if the password store is initialized. +if ! pass ls >/dev/null 2>&1; +then + cat <<- EOFF >&2 + __pass: this type requires the password store to be initialized. + See cdist-type__pass_init(7) and pass(1) for more information. + EOFF + exit 1; +fi + +# Generate a password if it does not already exist. +if [ ! -f "\${PASSWORD_STORE_DIR}/${__object_id:?}.gpg" ]; +then + # shellcheck disable=SC2086 + pass generate \$NOSYMB "${__object_id:?}" $LENGTH >/dev/null +fi + +# Send it out to the messages. +pass "${__object_id:?}" >> "${__messages_out:?}" + +EOF diff --git a/type/__pass/man.rst b/type/__pass/man.rst new file mode 100644 index 0000000..ea9b93c --- /dev/null +++ b/type/__pass/man.rst @@ -0,0 +1,73 @@ +cdist-type__pass(7) +=================== + +NAME +---- +cdist-type__pass - Generate and use passwords using pass(1). + + +DESCRIPTION +----------- +This type allows a user to generate and query passwords stored using pass(1) on +the host machine. The password is then printed to the cdist message system, so +types depending on this one should require it. This enables an administrator to +ensure a password exists using this type and then, from another type, use it as +need be. + + +REQUIRED PARAMETERS +------------------- +storedir + The host-local directory where the password store is to be found (or + created if it does not exist). + + +OPTIONAL PARAMETERS +------------------- +length + The length of the password to be created if it does not exist. Note that if + it exists, this has no effect (and hence will not update the password, even + if the length is different from the one specified). + + +BOOLEAN PARAMETERS +------------------ +no-symbols + If this parameter is set, then a newly generated password will only contain + alphanumeric characters, making it easier for typing by meatware. + + +EXAMPLES +-------- + +Assuming that __othertype takes the path of the password as an argument and +looks up in the cdist messages to find it: + +.. code-block:: sh + + require=__pass_init \ + __pass database/services/arandomservice \ + --storedir password/store/location + + require='__pass/database/services/arandomservice' \ + __othertype --password database/service/arandomservice + + +-- + +SEE ALSO +-------- +`pass`\ (7), `cdist-type__pass_init`\ (7) + + +AUTHORS +------- +Joachim Desroches + + +COPYING +------- +Copyright \(C) 2020 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__pass/parameter/boolean b/type/__pass/parameter/boolean new file mode 100644 index 0000000..8be3749 --- /dev/null +++ b/type/__pass/parameter/boolean @@ -0,0 +1 @@ +no-symbols diff --git a/type/__pass/parameter/optional b/type/__pass/parameter/optional new file mode 100644 index 0000000..7f5e3b6 --- /dev/null +++ b/type/__pass/parameter/optional @@ -0,0 +1 @@ +length diff --git a/type/__pass/parameter/required b/type/__pass/parameter/required new file mode 100644 index 0000000..f2fc3a2 --- /dev/null +++ b/type/__pass/parameter/required @@ -0,0 +1 @@ +storedir diff --git a/type/__pass_init/gencode-local b/type/__pass_init/gencode-local new file mode 100755 index 0000000..0be44d9 --- /dev/null +++ b/type/__pass_init/gencode-local @@ -0,0 +1,43 @@ +#!/bin/sh -e +# +# 2020 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +# Check pass is installed. +command -v pass >/dev/null 2>&1 || + { + cat <<- EOF >&2 + __pass_init: this type requires pass installed. + See https://www.passwordstore.org/. + EOF + exit 1; + } + +# Load required GPG ID parameters. +set -- +while read -r id; +do + set -- "$@" "$id" +done < "${__object:?}/parameter/gpgid" + +# Load required password store location parameter. +PASSWORD_STORE_DIR="$(cat "${__object:?}/parameter/storedir")" +export PASSWORD_STORE_DIR + +# Do our work. +pass init "$@" >/dev/null diff --git a/type/__pass_init/man.rst b/type/__pass_init/man.rst new file mode 100644 index 0000000..7a8d01e --- /dev/null +++ b/type/__pass_init/man.rst @@ -0,0 +1,56 @@ +cdist-type__pass_init(7) +======================== + +NAME +---- +cdist-type__pass_init - Initialize a local password store. + + +DESCRIPTION +----------- +This type is intented to be used as a prerequisite to the +cdist-type__pass(7) type. It will set up a pass(1) password +store with the provided GPP2(1) public encryption key IDs. + + +REQUIRED PARAMETERS +------------------- +storedir + The host-local directory where the password store is to be found (or + created if it does not exist). + + +REQUIRED MULTIPLE PARAMETERS +---------------------------- +gpgid + The GPG IDs of the public keys used to encrypt the password store. + + +EXAMPLES +-------- + +.. code-block:: sh + + # Setup a repository with a GPG ID + __pass_init + --storedir password/store/location + --gpgpid 92296965EAA1DD86A93284EF7B21E5AA32FB9810 + +-- + +SEE ALSO +-------- +`pass`\ (7), `cdist-type__pass`\ (7) + + +AUTHORS +------- +Joachim Desroches + + +COPYING +------- +Copyright \(C) 2021 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__pass_init/parameter/required b/type/__pass_init/parameter/required new file mode 100644 index 0000000..f2fc3a2 --- /dev/null +++ b/type/__pass_init/parameter/required @@ -0,0 +1 @@ +storedir diff --git a/type/__pass_init/parameter/required_multiple b/type/__pass_init/parameter/required_multiple new file mode 100644 index 0000000..bed3d4a --- /dev/null +++ b/type/__pass_init/parameter/required_multiple @@ -0,0 +1 @@ +gpgid diff --git a/type/__pass_init/singleton b/type/__pass_init/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__php_fpm/files/php.ini.sh b/type/__php_fpm/files/php.ini.sh new file mode 100755 index 0000000..ec7e446 --- /dev/null +++ b/type/__php_fpm/files/php.ini.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +cat < + + +COPYING +------- +Copyright \(C) 2022 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__php_fpm/manifest b/type/__php_fpm/manifest new file mode 100644 index 0000000..9c32716 --- /dev/null +++ b/type/__php_fpm/manifest @@ -0,0 +1,68 @@ +#!/bin/sh + +os=$(cat "${__global:?}/explorer/os") + +PHPVER=$(cat "${__object:?}/parameter/php-version") +export PHPVER + +case "$os" in + 'alpine') + # Alpine packages looks like php81-fpm - we make sure to remove dots from user + # input. + PHPVER=$(echo "$PHPVER" | tr -d '.') + + package="php${PHPVER}-fpm" + opcache_package="php${PHPVER}-opcache" + apcu_package="php${PHPVER}-pecl-apcu" + + service="php-fpm${PHPVER}" + php_confdir="/etc/php${PHPVER}" + php_ini="${php_confdir:?}/php.ini" + + PHP_INCLUDEDIR="/usr/share/php${PHPVER:?}" + export PHP_INCLUDEDIR + ;; + 'debian'|'ubuntu') + package="php${PHPVER}-fpm" + opcache_package="php${PHPVER}-opcache" + apcu_package="php${PHPVER}-apcu" + + service="php${PHPVER}-fpm" + php_confdir="/etc/php/${PHPVER}" + php_ini="${php_confdir:?}/fpm/php.ini" + + PHP_INCLUDEDIR="/usr/share/php/${PHPVER:?}" + export PHP_INCLUDEDIR + ;; + *) + printf "Your operating system is currently not supported by this type\n" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +__package "$package" +require="__package/$package" __start_on_boot "$service" + +if [ -f "${__object:?}/parameter/enable-opcache" ]; then + __package "$opcache_package" +fi + +if [ -f "${__object:?}/parameter/enable-apcu" ]; then + __package "$apcu_package" +fi + +MEMORY_LIMIT=$(cat "${__object:?}/parameter/memory-limit") +export MEMORY_LIMIT + +UPLOAD_MAX_FILESIZE=$(cat "${__object:?}/parameter/upload-max-filesize") +export UPLOAD_MAX_FILESIZE + +mkdir -p "${__object:?}/files" +"${__type:?}/files/php.ini.sh" >"${__object:?}/files/php.ini" + +require="__package/$package" __file "${php_ini:?}" \ + --mode 644 --source "${__object:?}/files/php.ini" \ + --onchange "service $service restart" + +require="__file/${php_ini:?}" __service "$service" --action start diff --git a/type/__php_fpm/parameter/boolean b/type/__php_fpm/parameter/boolean new file mode 100644 index 0000000..9964486 --- /dev/null +++ b/type/__php_fpm/parameter/boolean @@ -0,0 +1,2 @@ +enable-opcache +enable-apcu diff --git a/type/__php_fpm/parameter/default/memory-limit b/type/__php_fpm/parameter/default/memory-limit new file mode 100644 index 0000000..d95fe12 --- /dev/null +++ b/type/__php_fpm/parameter/default/memory-limit @@ -0,0 +1 @@ +512M diff --git a/type/__php_fpm/parameter/default/upload-max-filesize b/type/__php_fpm/parameter/default/upload-max-filesize new file mode 100644 index 0000000..5fbcf1c --- /dev/null +++ b/type/__php_fpm/parameter/default/upload-max-filesize @@ -0,0 +1 @@ +2M diff --git a/type/__php_fpm/parameter/optional b/type/__php_fpm/parameter/optional new file mode 100644 index 0000000..a41a87c --- /dev/null +++ b/type/__php_fpm/parameter/optional @@ -0,0 +1,2 @@ +upload-max-filesize +memory-limit diff --git a/type/__php_fpm/parameter/required b/type/__php_fpm/parameter/required new file mode 100644 index 0000000..173609d --- /dev/null +++ b/type/__php_fpm/parameter/required @@ -0,0 +1 @@ +php-version diff --git a/type/__php_fpm/singleton b/type/__php_fpm/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__php_fpm_pool/files/www.conf.sh b/type/__php_fpm_pool/files/www.conf.sh new file mode 100755 index 0000000..aa8fa7c --- /dev/null +++ b/type/__php_fpm_pool/files/www.conf.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +cat < + + +COPYING +------- +Copyright \(C) 2022 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__php_fpm_pool/manifest b/type/__php_fpm_pool/manifest new file mode 100644 index 0000000..3c8491a --- /dev/null +++ b/type/__php_fpm_pool/manifest @@ -0,0 +1,40 @@ +#!/bin/sh + +os=$(cat "${__global:?}/explorer/os") +name=${__object_id:?} + +PHPVER=$(cat "${__object:?}/parameter/php-version") +export PHPVER + +case "$os" in + 'alpine') + PHPVER=$(echo "$PHP_VERSION" | tr -d '.') + service="php-fpm${PHPVER}" + php_confdir="/etc/php${PHPVER}" + php_pooldir="${php_confdir:?}/php-fpm.d" + ;; + 'debian'|'ubuntu') + service="php${PHPVER}-fpm" + php_confdir="/etc/php/${PHPVER}" + php_pooldir="${php_confdir:?}/fpm/pool.d" + ;; + *) + printf "Your operating system is currently not supported by this type\n" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +POOL_NAME="$name" +POOL_USER=$(cat "${__object:?}/parameter/pool-user") +POOL_GROUP=$(cat "${__object:?}/parameter/pool-group") +POOL_LISTEN_ADDR=$(cat "${__object:?}/parameter/pool-listen-addr") +POOL_LISTEN_OWNER=$(cat "${__object:?}/parameter/pool-listen-owner") +export POOL_USER POOL_GROUP POOL_LISTEN_ADDR POOL_LISTEN_OWNER POOL_NAME + +mkdir -p "${__object:?}/files" +"${__type:?}/files/www.conf.sh" >"${__object:?}/files/www.conf" + +__file "${php_pooldir:?}/${name}.conf" \ + --mode 644 --source "${__object:?}/files/www.conf" \ + --onchange "service $service reload" diff --git a/type/__php_fpm_pool/parameter/optional b/type/__php_fpm_pool/parameter/optional new file mode 100644 index 0000000..7adc0a3 --- /dev/null +++ b/type/__php_fpm_pool/parameter/optional @@ -0,0 +1,2 @@ +memory-limit +open-basedir diff --git a/type/__php_fpm_pool/parameter/required b/type/__php_fpm_pool/parameter/required new file mode 100644 index 0000000..d247290 --- /dev/null +++ b/type/__php_fpm_pool/parameter/required @@ -0,0 +1,5 @@ +php-version +pool-user +pool-group +pool-listen-addr +pool-listen-owner diff --git a/type/__root_mail_dma/files/aliases b/type/__root_mail_dma/files/aliases deleted file mode 100644 index d341318..0000000 --- a/type/__root_mail_dma/files/aliases +++ /dev/null @@ -1,68 +0,0 @@ -# Based off FreeBSD's /etc/aliases -# -# >>>>>>>>>> The program "newaliases" must be run after -# >> NOTE >> this file is updated for any changes to -# >>>>>>>>>> show through to sendmail. -# -# -# See also RFC 2142, `MAILBOX NAMES FOR COMMON SERVICES, ROLES -# AND FUNCTIONS', May 1997 -# http://tools.ietf.org/html/rfc2142 - -# Pretty much everything else in this file points to "root", so -# you would do well in either reading root's mailbox or forwarding -# root's email from here. - -# root: me@my.domain - - -# Basic system aliases -- these MUST be present -MAILER-DAEMON: postmaster -postmaster: root - -# General redirections for pseudo accounts -_dhcp: root -_pflogd: root -auditdistd: root -bin: root -bind: root -daemon: root -games: root -hast: root -kmem: root -mailnull: postmaster -man: root -news: root -nobody: root -operator: root -pop: root -proxy: root -smmsp: postmaster -sshd: root -system: root -toor: root -tty: root -usenet: news -uucp: root - -# Well-known aliases -- these should be filled in! -manager: root -dumper: root - -# BUSINESS-RELATED MAILBOX NAMES -info: root -marketing: root -sales: root -support: root - -# NETWORK OPERATIONS MAILBOX NAMES -abuse: root -noc: root -security: root - -# SUPPORT MAILBOX NAMES FOR SPECIFIC INTERNET SERVICES -ftp: root -ftp-bugs: ftp -hostmaster: root -webmaster: root -www: webmaster diff --git a/type/__root_mail_dma/gencode-remote b/type/__root_mail_dma/gencode-remote deleted file mode 100755 index 2961c09..0000000 --- a/type/__root_mail_dma/gencode-remote +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -e - -if [ -f "${__object}/parameter/send-test-email" ]; then - SEND_EMAIL="YES" -fi - -if [ "${SEND_EMAIL}" != "YES" ]; then - exit 0 -fi - -cat <`_ -- `DragonFly Handbook MTA `_ - - -AUTHORS -------- -Evilham - - -COPYING -------- -Copyright \(C) 2020 Evilham. You can redistribute it -and/or modify it under the terms of the GNU General Public License as -published by the Free Software Foundation, either version 3 of the -License, or (at your option) any later version. diff --git a/type/__root_mail_dma/manifest b/type/__root_mail_dma/manifest deleted file mode 100755 index abcaa5b..0000000 --- a/type/__root_mail_dma/manifest +++ /dev/null @@ -1,153 +0,0 @@ -#!/bin/sh -e - -os="$(cat "${__global}/explorer/os")" - -root_email="$(tr '\n' ',' < "${__object}/parameter/root-email" | sed -E 's/,+$//')" -smart_host="$(cat "${__object}/parameter/smart-host")" - -if [ -f "${__object}/parameter/mailname" ]; then - mailname="$(cat "${__object}/parameter/mailname")" -else - # default mailname behaviour is different in certain systems - case ${os} in - debian|devuan|ubuntu) - # Debian-like default to /etc/mailname - mailname="/etc/mailname" - ;; - *) - # Otherwise let's use the hostname - mailname="${__target_host}" - ;; - esac -fi - -aliases_file=/etc/mail/aliases -case ${os} in - debian|devuan|ubuntu) - # Debian-like requires installing DMA - __package dma - # Moving forward without DMA doesn't make much sense - export require="__package/dma" - aliases_file=/etc/aliases - ;; - freebsd) - # Disable sendmail + stop if necessary - __key_value \ - --file "/etc/rc.conf" \ - --comment "# Disable sendmail " \ - --key "sendmail_enable" \ - --delimiter "=" \ - --value "NONE" \ - --onchange "service sendmail onestop || true" \ - "sendmail_enable" - # Setup mailwrapper accordingly - __file /etc/mail/mailer.conf \ - --mode 0644 \ - --source '-' < /dev/stderr < + +COPYING +------- +Copyright \(C) 2020 Evilham. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__runit/manifest b/type/__runit/manifest new file mode 100755 index 0000000..6e5feca --- /dev/null +++ b/type/__runit/manifest @@ -0,0 +1,30 @@ +#!/bin/sh -e + +__package "runit" + +os="$(cat "${__global}/explorer/os")" +case "${os}" in + debian|devuan) + # zero-config sysvinit and systemd compatibility + os_version="$(cat "${__global}/explorer/os_version")" + debian_package="runit-run" + case "${os_version}" in + beowulf) + debian_package="runit" + ;; + esac + __package "${debian_package}" + ;; + freebsd) + __key_value \ + --file "/etc/rc.conf" \ + --key "runsvdir_enable" \ + --delimiter "=" \ + --value "yes" \ + "runsvdir_enable" + ;; + *) + echo "Your OS '${os}' is currently not supported." >&2 + exit 1 + ;; +esac diff --git a/type/__runit/singleton b/type/__runit/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__runit_service/man.rst b/type/__runit_service/man.rst new file mode 100644 index 0000000..edd19e3 --- /dev/null +++ b/type/__runit_service/man.rst @@ -0,0 +1,63 @@ +cdist-type__runit_service(7) +==================================== + +NAME +---- +cdist-type__runit_service - Create a runit-compatible service dir. + + +DESCRIPTION +----------- +Create a directory structure compatible with runit-like service management. + +Note that sv(8) and runsvdir(8) must be present on the target system, this can +be achieved with e.g. `__runit`. + +The `__object_id` will be used as the service name. + + +REQUIRED PARAMETERS +------------------- +source + File to save as /run. If set to '-', standard input will be used. + + +BOOLEAN PARAMETERS +------------------ +log + Setup logging with `svlogd -tt ./main`. + +OPTIONAL PARAMETERS +------------------- +state + Whether this service is to be 'present' (default) or 'absent'. + + +EXAMPLES +-------- + +.. code-block:: sh + + require="__runit" __runit_service tasksched \ + --source - << EOF + #!/bin/sh -e + cd "${HOME}/.local/share/tasksched" + exec ./server.js 2>&1 + EOF + + +SEE ALSO +-------- +:strong:`cdist-type__runit`\ (7) + + +AUTHORS +------- +Evilham + +COPYING +------- +Copyright \(C) 2020 Evilham. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__runit_service/manifest b/type/__runit_service/manifest new file mode 100755 index 0000000..548a1de --- /dev/null +++ b/type/__runit_service/manifest @@ -0,0 +1,57 @@ +#!/bin/sh -e + +os="$(cat "${__global}/explorer/os")" +case "${os}" in + debian|devuan) + svdir="/etc/service" + ;; + *bsd) + svdir="/var/service" + ;; + *) + echo "Your OS '${OS}' is currently not supported." >&2 + exit 1 + ;; +esac + +sv="${__object_id}" +state="$(cat "${__object}/parameter/state")" +run_file="${svdir}/${sv}/run" + +source="$(cat "$__object/parameter/source")" +if [ "$source" = "-" ]; then + source="$__object/stdin" +fi + +# Create this service's directory +__directory --state "${state}" "${svdir}/${sv}" + +export require="__directory${svdir}/${sv}" + +if [ "${state}" != "present" ]; then + # We are done here, the service gets removed + exit +fi + +# Setup run file +__file --state "${state}" --mode 0550 --source "${source}" \ + --onchange "sv restart '${sv}' || true" \ + "${run_file}" +export require="${require} __file${run_file}" + +if [ -f "${__object}/parameter/log" ]; then + # Setup logger if requested + logdir="/var/log/runit" + __directory --parents "${svdir}/${sv}/log" + __directory --state absent "${svdir}/${sv}/log/main" # Remove lingering old fashioned log + __directory --parents "${logdir}/${sv}" + export require="${require} __directory${svdir}/${sv}/log __directory${logdir}/${sv}" + __file "${svdir}/${sv}/log/run" \ + --state "${state}" \ + --mode 0755 \ + --onchange "sv restart '${sv}/log' || true" \ + --source "-" < + + +COPYING +------- +Copyright \(C) 2022 Evilham. diff --git a/type/__single_binary_service/manifest b/type/__single_binary_service/manifest new file mode 100755 index 0000000..f46d62e --- /dev/null +++ b/type/__single_binary_service/manifest @@ -0,0 +1,358 @@ +#!/bin/sh -eu +SERVICE_NAME="${__object_id}" + +OS="$(cat "${__global}/explorer/os")" + +case "${OS}" in + debian|devuan) + SUPER_USER_GROUP=root + ETC_DIR="/etc" + ;; + *bsd) + SUPER_USER_GROUP=wheel + ETC_DIR="/usr/local/etc" + ;; + *) + echo "Your OS '${OS}' is currently not supported." >&2 + exit 1 + ;; +esac +INIT="$(cat "${__global}/explorer/init")" + +case "${INIT}" in + systemd) + service_definition_require="__systemd_unit/${SERVICE_NAME}.service" + service_command="service ${SERVICE_NAME} %s" + ;; + runit|sysvinit) + # We will use runit to manage these services + __runit + export require="__runit" + service_definition_require="__runit_service/${SERVICE_NAME}" + service_command="sv %s ${SERVICE_NAME}" + ;; + *) + echo "Init system '${INIT}' is currently not supported." >&2 + exit 1 + ;; +esac + +BIN_DIR="/usr/local/bin" + +# Ensure the target bin dir exists +# Care, we never want to remove it :-D +__directory "${BIN_DIR}" \ + --state "exists" \ + --mode 0755 +export require="${require:-} __directory${BIN_DIR}" + +STATE="$(cat "${__object}/parameter/state")" +USER="$(cat "${__object}/parameter/user")" +GROUP="$(cat "${__object}/parameter/group" 2>/dev/null || true)" +if [ -z "${GROUP}" ]; then + if [ "${USER}" != "root" ]; then + GROUP="${USER}" + else + GROUP="${SUPER_USER_GROUP}" + fi +fi + + +BINARY="$(cat "${__object}/parameter/binary" 2>/dev/null || true)" +if [ -z "${BINARY}" ]; then + BINARY="${SERVICE_NAME}" +fi +EXTRA_BINARIES="$(cat "${__object}/parameter/extra-binary" 2>/dev/null || true)" +# This only makes sense for file archives +if [ -n "${EXTRA_BINARIES}" ] && [ -f "${__object}/parameter/unpack" ]; then + cat >&2 <<-EOF + You cannot specify extra binaries without the --unpack argument. + Make sure that the --url argument points to a file archive. +EOF +fi + +SERVICE_EXEC="$(cat "${__object}/parameter/service-exec" 2>/dev/null || true)" +if [ -z "${SERVICE_EXEC}" ]; then + SERVICE_EXEC="${BIN_DIR}/${BINARY}" +fi +SERVICE_ARGS="$(cat "${__object}/parameter/service-args")" +SERVICE_EXEC="${SERVICE_EXEC} ${SERVICE_ARGS}" + +SERVICE_DESCRIPTION="$(cat "${__object}/parameter/service-description" \ + 2>/dev/null || true)" +if [ -z "${SERVICE_DESCRIPTION}" ]; then + SERVICE_DESCRIPTION="cdist-managed '${SERVICE_NAME}' service" +fi + +SERVICE_DEFINITION="$(cat "${__object}/parameter/service-definition" 2>/dev/null || true)" + +CHECKSUM="$(cat "${__object}/parameter/checksum")" +SHOULD_VERSION="$(cat "${__object}/parameter/version" 2>/dev/null || true)" +DOWNLOAD_URL="$(cat "${__object}/parameter/url")" +LOCAL_SOURCE="$(cat "${__object}/parameter/local-source")" +if [ "${STATE}" = "present" ] && [ -z "${SHOULD_VERSION}" ]; then + cat >&1 <<-EOM + When installing a service, --version must be specified. + EOM + exit 1 +fi +if [ "${STATE}" = "present" ] && [ -z "${DOWNLOAD_URL}${LOCAL_SOURCE}" ]; then + cat >&1 <<-EOM + Exactly one of --url or --local-source must be specified. + EOM + exit 1 +fi +if [ -n "${DOWNLOAD_URL}" ] && [ -z "${CHECKSUM}" ]; then + cat >&1 <<-EOM + You must specify --checksum when using --url. + EOM + exit 1 +fi +if [ "${LOCAL_SOURCE}" = "-" ]; then + LOCAL_SOURCE="${__object}/stdin" +fi + +# Create a user for the service if it is not root +USER_HOME_DIR="/root" +require_user_created="" +service_require="" +if [ "${USER}" != "root" ] && \ + [ ! -f "${__object}/parameter/do-not-manage-user" ]; then + if [ "${STATE}" = "absent" ]; then + # When removing, ensure user is not being used + user_require="${service_definition_require}" + fi + USER_HOME_DIR="$(cat "${__object}/parameter/user-home-dir")" + if [ "${USER_HOME_DIR}" != "/nonexistent" ]; then + USER_CREATE_HOME="--create-home" + fi + require="${require} ${user_require:-}" __user "${USER}" \ + --system \ + --state "${STATE}" \ + --home "${USER_HOME_DIR}" \ + --comment "cdist-managed service user" \ + ${USER_CREATE_HOME} + require_user_created="__user/${USER}" + # Track dependencies + service_require="${service_require} ${require_user_created}" +fi + +# Adapt directory permissions when necessary +WORKING_DIRECTORY_PERMISSIONS="$(cat "${__object}/parameter/working-directory-permissions")" +WORKING_DIRECTORY_PATH="$(cat "${__object}/parameter/working-directory" 2>/dev/null || true)" +if [ -n "${WORKING_DIRECTORY_PATH}" ]; then + WORKING_DIRECTORY_SYSTEMD="WorkingDirectory=${WORKING_DIRECTORY_PATH}" + WORKING_DIRECTORY_RUNIT="cd '${WORKING_DIRECTORY_PATH}'" + require="${require_user_created}" __directory \ + "${WORKING_DIRECTORY_PATH}" --state present \ + --mode "${WORKING_DIRECTORY_PERMISSIONS}" \ + --owner "${USER}" --group "${GROUP}" +fi + +# Place config file if necessary +CONFIG_FILE_DEST="$(cat "${__object}/parameter/config-file-destination" 2>/dev/null || true)" +if [ -z "${CONFIG_FILE_DEST}" ]; then + CONFIG_FILE_DEST="${ETC_DIR}/${SERVICE_NAME}.conf" +else + require="${require_user_created}" __directory \ + "$(dirname "${WORKING_DIRECTORY_PATH}")" --state present \ + --mode "${WORKING_DIRECTORY_PERMISSIONS}" \ + --owner "${USER}" --group "${GROUP}" +fi +CONFIG_FILE_SOURCE="$(cat "${__object}/parameter/config-file-source" 2>/dev/null || true)" +if [ "${CONFIG_FILE_SOURCE}" = "-" ]; then + CONFIG_FILE_SOURCE="${__object}/stdin" +fi +if [ -n "${CONFIG_FILE_SOURCE}" ] && [ "${STATE}" = "present" ]; then + require="${require} ${require_user_created}" __file \ + "${CONFIG_FILE_DEST}" \ + --owner "${USER}" \ + --group "${GROUP}" \ + --mode "0440" \ + --source "${CONFIG_FILE_SOURCE}" + service_require="${service_require} __file${CONFIG_FILE_DEST}" +fi + + + +# These messages will trigger a service restart (overridden for systemd) +service_config_reload_pattern="^__file${CONFIG_FILE_DEST}" + +# This should setup the object in $service_definition_require +# See above. +case "${INIT}" in + systemd) + if [ -z "${SERVICE_DEFINITION}" ]; then + SYSTEMD_ENV_FILE="/etc/systemd/system/${SERVICE_NAME}.env" + __file "${SYSTEMD_ENV_FILE}" \ + --mode 0400 \ + --source "${__object}/parameter/env" + # We need to take into account the envionment file for systemd too + service_config_reload_pattern="(${service_config_reload_pattern}|^__file${SYSTEMD_ENV_FILE})" + + SERVICE_DEFINITION="$(cat <&1 +exec chpst -u "${USER}:${GROUP}" ${SERVICE_EXEC} +EOF +)" + fi + __runit_service "${SERVICE_NAME}" \ + --state "${STATE}" \ + --log \ + --source - </dev/null || true)" + # Place packed file + if [ -n "${DOWNLOAD_URL}" ]; then + __download "${TMP_PATH}${UNPACK_EXTENSION}" \ + --url "${DOWNLOAD_URL}" \ + --download remote \ + --sum "${CHECKSUM}" + require_place_file="__download${TMP_PATH}${UNPACK_EXTENSION}" + else + # TODO: this doesn't use CHECKSUM + __file "${TMP_PATH}${UNPACK_EXTENSION}" \ + --source "${LOCAL_SOURCE}" + require_place_file="__file${TMP_PATH}${UNPACK_EXTENSION}" + fi + + # Unpack file and also perform service upgrade + # shellcheck disable=SC2086 + require="${require_place_file}" \ + __unpack "${TMP_PATH}${UNPACK_EXTENSION}" \ + ${UNPACK_ARGS} \ + --destination "${TMP_PATH}" + version_bump_require="__unpack${TMP_PATH}${UNPACK_EXTENSION}" + else + # Create temp directory + __directory "${TMP_PATH}" + # Place in temp directory with the specified binary name + if [ -n "${DOWNLOAD_URL}" ]; then + require="__directory${TMP_PATH}" __download \ + "${TMP_PATH}/${BINARY}" \ + --url "${DOWNLOAD_URL}" \ + --download remote \ + --sum "${CHECKSUM}" + version_bump_require="__download${TMP_PATH}/${BINARY}" + else + require="__directory${TMP_PATH}" __file \ + "${TMP_PATH}/${BINARY}" \ + --source "${LOCAL_SOURCE}" + version_bump_require="__file${TMP_PATH}/${BINARY}" + fi + fi + + # Perform update of cdist-managed version file + # And also perform service upgrade + # This is a bug if service_upgrade fails >,< + printf "%s" "${SHOULD_VERSION}" | \ + require="${version_bump_require}" __file \ + "${VERSION_FILE}" \ + --onchange "${perform_service_upgrade}" \ + --source "-" +else + # We only restart here if there was a config or env change + # but there was not a version change + require="${service_require}" __check_messages \ + "single_binary_service_${__object_id}" \ + --pattern "${service_config_reload_pattern}" \ + --execute "$(sv_cmd restart)" +fi diff --git a/type/__single_binary_service/parameter/boolean b/type/__single_binary_service/parameter/boolean new file mode 100644 index 0000000..a779fd5 --- /dev/null +++ b/type/__single_binary_service/parameter/boolean @@ -0,0 +1,2 @@ +do-not-manage-user +unpack diff --git a/type/__single_binary_service/parameter/default/checksum b/type/__single_binary_service/parameter/default/checksum new file mode 100644 index 0000000..e69de29 diff --git a/type/__single_binary_service/parameter/default/env b/type/__single_binary_service/parameter/default/env new file mode 100644 index 0000000..e69de29 diff --git a/type/__single_binary_service/parameter/default/local-source b/type/__single_binary_service/parameter/default/local-source new file mode 100644 index 0000000..e69de29 diff --git a/type/__single_binary_service/parameter/default/service-args b/type/__single_binary_service/parameter/default/service-args new file mode 100644 index 0000000..e69de29 diff --git a/type/__single_binary_service/parameter/default/state b/type/__single_binary_service/parameter/default/state new file mode 100644 index 0000000..e7f6134 --- /dev/null +++ b/type/__single_binary_service/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/type/__single_binary_service/parameter/default/unpack-extension b/type/__single_binary_service/parameter/default/unpack-extension new file mode 100644 index 0000000..c95e2e9 --- /dev/null +++ b/type/__single_binary_service/parameter/default/unpack-extension @@ -0,0 +1 @@ +.tar.gz \ No newline at end of file diff --git a/type/__single_binary_service/parameter/default/url b/type/__single_binary_service/parameter/default/url new file mode 100644 index 0000000..e69de29 diff --git a/type/__single_binary_service/parameter/default/user b/type/__single_binary_service/parameter/default/user new file mode 100644 index 0000000..d8649da --- /dev/null +++ b/type/__single_binary_service/parameter/default/user @@ -0,0 +1 @@ +root diff --git a/type/__single_binary_service/parameter/default/user-home-dir b/type/__single_binary_service/parameter/default/user-home-dir new file mode 100644 index 0000000..4d21ca6 --- /dev/null +++ b/type/__single_binary_service/parameter/default/user-home-dir @@ -0,0 +1 @@ +/nonexistent diff --git a/type/__single_binary_service/parameter/default/working-directory-permissions b/type/__single_binary_service/parameter/default/working-directory-permissions new file mode 100644 index 0000000..4cd9d53 --- /dev/null +++ b/type/__single_binary_service/parameter/default/working-directory-permissions @@ -0,0 +1 @@ +0750 diff --git a/type/__single_binary_service/parameter/optional b/type/__single_binary_service/parameter/optional new file mode 100644 index 0000000..aaed0ac --- /dev/null +++ b/type/__single_binary_service/parameter/optional @@ -0,0 +1,20 @@ +checksum +config-file-source +config-file-destination +env +user +group +state +binary +local-source +service-args +service-exec +service-description +service-definition +unpack-extension +unpack-args +url +user-home-dir +version +working-directory +working-directory-permissions diff --git a/type/__single_binary_service/parameter/optional_multiple b/type/__single_binary_service/parameter/optional_multiple new file mode 100644 index 0000000..e1ca562 --- /dev/null +++ b/type/__single_binary_service/parameter/optional_multiple @@ -0,0 +1 @@ +extra-binary diff --git a/type/__systemd_network/gencode-remote b/type/__systemd_network/gencode-remote new file mode 100755 index 0000000..13c16c9 --- /dev/null +++ b/type/__systemd_network/gencode-remote @@ -0,0 +1,20 @@ +#!/bin/sh -e +# +# 2022 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . + +echo "systemctl enable systemd-networkd" diff --git a/type/__systemd_network/man.rst b/type/__systemd_network/man.rst new file mode 100644 index 0000000..1b7b7a6 --- /dev/null +++ b/type/__systemd_network/man.rst @@ -0,0 +1,68 @@ +cdist-type__systemd-network(7) +============================== + +NAME +---- +cdist-type__systemd-network - Configure systemd.network(5) file. + + +DESCRIPTION +----------- + +This type allows you to configure network interfaces by generating a +systemd.network(5) file. It will enable systemd-networkd, so be sure to remove +any conflicting network configuration tool if appropriate! + +Note that the systemd.network(5) system is very complete, and this type does +not aim at providing every possible option. Are currently available only the +most common options: feel free to add anything you need to this type which +hopefully will grow over time. + + +REQUIRED PARAMETERS +------------------- +None. + + +OPTIONAL PARAMETERS +------------------- +description + A text field used when displaying details about this network. + +OPTIONAL MULTIPLE PARAMETERS +---------------------------- +match-name + A text field that will be set in the `Name` option of the `[Match]` section. + + +BOOLEAN PARAMETERS +------------------ +ipv6ra-usedomains + Set the `UseDomains` option of the `[IPv6AcceptRA]` section to `True`. + + +EXAMPLES +-------- + +.. code-block:: sh + + # TODO + __systemd-network + + +SEE ALSO +-------- +`cdist-type_systemd-resolved`\ (7) +`systemd.network`\ (5) + +AUTHORS +------- +Joachim Desroches + + +COPYING +------- +Copyright \(C) 2022 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__systemd_network/manifest b/type/__systemd_network/manifest new file mode 100755 index 0000000..49eb792 --- /dev/null +++ b/type/__systemd_network/manifest @@ -0,0 +1,86 @@ +#!/bin/sh -e +# +# 2022 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +os=$(cat "${__global:?}/explorer/os") + +case "$os" in +'debian' | 'ubuntu' | 'archlinux') + : + ;; +*) + printf "Your operating system (%s) is currently not supported by systemd-network\n" "$os" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +# XXX: Please keep the option parsing organized in order per-section, with +# sections in the same order as they are in the manpage. This will make hacking +# and maintaining this type much easier. + +mkdir "${__object:?}/files" +output_file="${__object:?}/files/${__object_id:?}.network" + +cat << EOF > "$output_file" +# This file is managed by cdist. Do not edit by hand! +EOF + +# Match section +# Ensure section is needed, OR existence of optional params. +if [ -f "${__object:?}/parameter/match-name" ]; +then + printf "\n[Match]\n" >> "$output_file" + + if [ -f "${__object:?}/parameter/match-name" ]; + then + sed -e 's/^/Name=/' \ + "${__object:?}/parameter/match-name" >> "$output_file" + fi +fi + +# Network section +# Ensure section is needed, OR existence of optional params. +if [ -f "${__object:?}/parameter/description" ]; +then + printf "\n[Network]\n" >> "$output_file" + + if [ -f "${__object:?}/parameter/description" ]; + then + sed -e 's/^/Description=/' \ + "${__object:?}/parameter/description" >> "$output_file" + fi +fi + +# IPv6AcceptRA section +# Ensure section is needed, OR existence of optional params. +if [ -f "${__object:?}/parameter/ipv6ra-usedomains" ]; +then + printf "\n[IPv6AcceptRA]\n" >> "$output_file" + + if [ -f "${__object:?}/parameter/ipv6ra-usedomains" ]; + then + printf "UseDomains=True\n" >> "$output_file" + fi + +fi + +__file "/etc/systemd/network/${__object_id:?}.network" \ + --source "$output_file" \ + --mode 0644 diff --git a/type/__systemd_network/parameter/boolean b/type/__systemd_network/parameter/boolean new file mode 100644 index 0000000..b23dcdc --- /dev/null +++ b/type/__systemd_network/parameter/boolean @@ -0,0 +1 @@ +ipv6ra-usedomains diff --git a/type/__systemd_network/parameter/optional b/type/__systemd_network/parameter/optional new file mode 100644 index 0000000..e1b39b0 --- /dev/null +++ b/type/__systemd_network/parameter/optional @@ -0,0 +1 @@ +description diff --git a/type/__systemd_network/parameter/optional_multiple b/type/__systemd_network/parameter/optional_multiple new file mode 100644 index 0000000..c97c387 --- /dev/null +++ b/type/__systemd_network/parameter/optional_multiple @@ -0,0 +1 @@ +match-name diff --git a/type/__systemd_resolved/gencode-remote b/type/__systemd_resolved/gencode-remote new file mode 100755 index 0000000..115b99b --- /dev/null +++ b/type/__systemd_resolved/gencode-remote @@ -0,0 +1,21 @@ +#!/bin/sh -e +# +# 2022 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +echo "systemctl enable systemd-resolved" diff --git a/type/__systemd_resolved/man.rst b/type/__systemd_resolved/man.rst new file mode 100644 index 0000000..213c725 --- /dev/null +++ b/type/__systemd_resolved/man.rst @@ -0,0 +1,47 @@ +cdist-type__systemd_resolved(7) +=============================== + +NAME +---- +cdist-type__systemd_resolved - Configure system to use systemd-resolved. + + +DESCRIPTION +----------- +*systemd-resolved* is a systemd service that provides network name resolution +to local applications via a D-Bus interface, the resolve NSS service +(nss-resolve(8)), and a local DNS stub listener on 127.0.0.53. + +This type enables and starts this type, and helps with some minimal +configuration. In particular, systemd-resolved has four modes of handling the +`/etc/resolv.conf` file: stub, static, uplink and foreign. See the +systemd-resolved(8) manpage for details. By default, this type uses stub mode: +if you need another one, please provide an implementation in this type! + + +EXAMPLES +-------- + +.. code-block:: sh + + __systemd_resolved + + +SEE ALSO +-------- +`systemd.network`\ (5) +`systemd-resolved`\ (8) +`nss-resolve`\ (8) + + +AUTHORS +------- +Joachim Desroches + + +COPYING +------- +Copyright \(C) 2022 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__systemd_resolved/manifest b/type/__systemd_resolved/manifest new file mode 100755 index 0000000..3b99592 --- /dev/null +++ b/type/__systemd_resolved/manifest @@ -0,0 +1,42 @@ +#!/bin/sh -e +# +# 2022 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +os=$(cat "${__global:?}/explorer/os") + +case "$os" in +'debian') + : + ;; +*) + printf "Your operating system (%s) is currently not supported by __systemd_resolved\n" "$os" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +__link /etc/resolv.conf \ + --type symbolic \ + --source ../run/systemd/resolve/stub-resolv.conf + +require=__link/etc/resolv.conf \ + __systemd_service systemd-resolved \ + --state running \ + --action restart \ + --if-required diff --git a/type/__systemd_resolved/singleton b/type/__systemd_resolved/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__uacme_account/gencode-remote b/type/__uacme_account/gencode-remote new file mode 100644 index 0000000..b75d2d7 --- /dev/null +++ b/type/__uacme_account/gencode-remote @@ -0,0 +1,47 @@ +#!/bin/sh + +os="$(cat "${__global:?}"/explorer/os)" + +case "$os" in + alpine|ubuntu|debian) + default_confdir=/etc/ssl/uacme + ;; + *) + echo "This type currently has no implementation for $os. Aborting." >&2; + exit 1 + ;; +esac + +admin_mail= +if [ -f "${__object:?}/parameter/admin-mail" ]; +then + admin_mail="$(cat "${__object:?}/parameter/admin-mail")"; +fi + +# Autoaccept ACME server terms (if any) upon new account creation. +uacme_opts="--yes" + +# Non-default ACMEv2 server directory object URL. +if [ -f "${__object:?}/parameter/acme-url" ]; then + custom_acme_url=$(cat "${__object:?}/parameter/acme-url") + uacme_opts="$uacme_opts --acme-url $custom_acme_url" +fi + +# Specify RFC8555 External Account Binding credentials. +if [ -f "${__object:?}/parameter/eab-credentials" ]; then + eab_credentials=$(cat "${__object:?}/parameter/eab-credentials") + uacme_opts="$uacme_opts --eab $eab_credentials" +fi + +confdir="${default_confdir:?}" +if [ -f "${__object:?}/parameter/confdir" ]; +then + confdir="$(cat "${__object:?}/parameter/confdir")" +fi + +cat << EOF +if ! [ -f "${confdir}/private/key.pem" ]; +then + uacme $uacme_opts new ${admin_mail} +fi +EOF diff --git a/type/__uacme_account/man.rst b/type/__uacme_account/man.rst new file mode 100644 index 0000000..c18bb40 --- /dev/null +++ b/type/__uacme_account/man.rst @@ -0,0 +1,63 @@ +cdist-type__uacme_account(7) +============================ + +NAME +---- +cdist-type__uacme_account - Install uacme and register Let's Encrypt account. + + +DESCRIPTION +----------- + +This type is used to bootstrap acquiring certificates from the Let's Encrypt +C.A by creating an account and accepting terms of use. The +`cdist-type__uacme_obtain(7)` type instances expect to depend on this type. + + +OPTIONAL PARAMETERS +------------------- +confdir + An alternative configuration directory for uacme's private keys and + certificates. + +admin-mail + Administrative contact email to register the account with. + +acme-url + ACMEv2 server directory object URL. Lets'Encrypt is used by default. + +eab-credentials + Specify RFC8555 External Account Binding credentials according to + https://tools.ietf.org/html/rfc8555#section-7.3.4, in order to associate a new + ACME account with an existing account in a non-ACME system such as a CA + customer database. KEYID must be an ASCII string. KEY must be + base64url-encoded. This is parameter is not supported by uacme < 1.6. + +EXAMPLES +-------- + +.. code-block:: sh + + # Create account with default settings for the OS. + __uacme_account + + # Create an account with email and custom location. + __uacme_account --confdir /opt/custom/uacme --admin-mail admin@domain.tld + + +SEE ALSO +-------- +:strong:`cdist-type__letsencrypt_cert`\ (7) +:strong:`cdist-type__uacme_obtain`\ (7) + +AUTHORS +------- +Joachim Desroches +Timothée Floure + +COPYING +------- +Copyright \(C) 2020 Joachim Desroches. You can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or (at your option) any +later version. diff --git a/type/__uacme_account/manifest b/type/__uacme_account/manifest new file mode 100644 index 0000000..0515853 --- /dev/null +++ b/type/__uacme_account/manifest @@ -0,0 +1,14 @@ +#!/bin/sh + +os="$(cat "${__global:?}"/explorer/os)" + +case "$os" in + "alpine"|"debian"|"ubuntu") + uacme_package=uacme + ;; + *) + echo "__uacme_account is not yet implemented for os $os. Aborting." >&2; + exit 1; +esac + +__package $uacme_package diff --git a/type/__uacme_account/parameter/optional b/type/__uacme_account/parameter/optional new file mode 100644 index 0000000..dff247c --- /dev/null +++ b/type/__uacme_account/parameter/optional @@ -0,0 +1,4 @@ +confdir +admin-mail +acme-url +eab-credentials diff --git a/type/__uacme_account/singleton b/type/__uacme_account/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__uacme_obtain/files/renew.sh.sh b/type/__uacme_obtain/files/renew.sh.sh new file mode 100755 index 0000000..dc82fd9 --- /dev/null +++ b/type/__uacme_obtain/files/renew.sh.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +cat << EOF +#!/bin/sh + +UACME_CHALLENGE_PATH=${CHALLENGEDIR:?} +export UACME_CHALLENGE_PATH + +# Issue certificate. +uacme -c ${CONFDIR:?} -h ${HOOKSCRIPT:?} ${DISABLE_OCSP?} ${ACME_URL?} \\ + ${EAB_CREDENTIALS?} ${MUST_STAPLE?} ${KEYTYPE?} issue -- ${DOMAIN:?} + +# Note: exit code 0 means that certificate was issued. +# Note: exit code 1 means that certificate was still valid, hence not renewed. +# Note: exit code 2 means that something went wrong. +status=\$? + +# All is well: we can stop now. +if [ \$status -eq 1 ]; +then + exit 0 +fi + +# An error occured. +if [ \$status -eq 2 ]; then + echo "Failed to renew certificate - exiting." >&2 + exit 1 +fi +EOF + +# Re-deploy, if needed. +if [ -n "${KEY_TARGET?}" ] && [ -n "${CERT_TARGET?}" ]; +then +cat << EOF + +# Deploy newly issued certificate. +set -e + +CERT_SOURCE=${CONFDIR:?}/${MAIN_DOMAIN:?}/cert.pem +KEY_SOURCE=${CONFDIR:?}/private/${MAIN_DOMAIN:?}/key.pem + +mkdir -p -- $(dirname "${CERT_TARGET?}") $(dirname "${KEY_TARGET?}") + +if ! cmp \${CERT_SOURCE:?} ${CERT_TARGET?} >/dev/null 2>&1; then + install -m 0640 \${KEY_SOURCE:?} ${KEY_TARGET?} + install -m 0644 \${CERT_SOURCE:?} ${CERT_TARGET?} + chown ${OWNER?} ${KEY_TARGET?} ${CERT_TARGET?} + + ${RENEW_HOOK?} +fi +EOF +fi diff --git a/type/__uacme_obtain/gencode-remote b/type/__uacme_obtain/gencode-remote new file mode 100644 index 0000000..739fc92 --- /dev/null +++ b/type/__uacme_obtain/gencode-remote @@ -0,0 +1,24 @@ +#!/bin/sh + +# FIXME: this code is duplicated from the manifest -> let's share it somehow. + +os="$(cat "${__global:?}"/explorer/os)" +case "$os" in + alpine|ubuntu|debian) + default_confdir=/etc/ssl/uacme + ;; + *) + echo "__uacme_obtain currently has no implementation for $os. Aborting." >&2; + exit 1; + ;; +esac + +confdir="${default_confdir:?}" +if [ -f "${__object:?}/parameter/confdir" ]; +then + confdir="$(cat "${__object:?}/parameter/confdir")" +fi + +# Run renew script 'by hand' for intial issue - renews will be handled by the +# cronjob. +echo "$confdir/${__object_id:?}/renew.sh" diff --git a/type/__uacme_obtain/man.rst b/type/__uacme_obtain/man.rst new file mode 100644 index 0000000..16ebe87 --- /dev/null +++ b/type/__uacme_obtain/man.rst @@ -0,0 +1,82 @@ +cdist-type__uacme_obtain(7) +=========================== + +NAME +---- +cdist-type__uacme_obtain - obtain, renew and deploy Let's Encrypt certificates + +DESCRIPTION +----------- + +This type leverage uacme to issue and renew Let's Encrypt certificates and +provides a simple deployment mechanism. It is expected to be called after +`__uacme_account`. + +REQUIRED PARAMETERS +------------------- +None. + +OPTIONAL PARAMETERS +------------------- +challengedir + Path to publicly available (served by a third-party HTTP server, under + `$DOMAIN/.well-known/acme-challenge`) challenge directory. + +confdir + uacme configuration directory. + +hookscript + Path to the challenge hook program. + +owner + Owner of installed certificate (e.g. `www-data`), passed to `chown`. + +install-cert-to + Installation path of the issued certificate. + +install-key-to + Installation path of the certificate's private key. + +renew-hook + Renew hook executed on certificate renewal (e.g. `service nginx reload`, `-` + for the standard input). + +force-cert-ownership-to + Override default ownership for TLS certificate, passed as argument to chown. + +OPTIONAL MULTIPLE PARAMETERS +---------------------------- +altdomains + Alternative domain names for this certificate. + +BOOLEAN PARAMETERS +------------------ +no-ocsp + When this flag is *not* specified and the certificate has an Authority + Information Access extension with an OCSP server location *uacme* makes an + OCSP request to the server; if the certificate is reported as revoked *uacme* + forces reissuance regardless of the expiration date. + +must-staple + Request certificates with the RFC7633 Certificate Status Request + TLS Feature Extension, informally also known as "OCSP Must-Staple". + +use-rsa + Use RSA instead of EC for the private key. Only applies to newly generated keys. + +SEE ALSO +-------- +:strong:`cdist-type__letsencrypt_cert`\ (7) +:strong:`cdist-type__uacme_account`\ (7) + +AUTHORS +------- +Joachim Desroches +Timothée Floure + +COPYING +------- +Copyright \(C) 2020 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__uacme_obtain/manifest b/type/__uacme_obtain/manifest new file mode 100644 index 0000000..a40119b --- /dev/null +++ b/type/__uacme_obtain/manifest @@ -0,0 +1,141 @@ +#!/bin/sh + +os="$(cat "${__global:?}"/explorer/os)" +case "$os" in + alpine|ubuntu|debian) + __package uacme + + default_challengedir=/var/www/.well-known/acme-challenge + default_hookscript=/usr/share/uacme/uacme.sh + default_confdir=/etc/ssl/uacme + ;; + *) + echo "__uacme_obtain currently has no implementation for $os. Aborting." >&2; + exit 1; + ;; +esac + +CHALLENGEDIR=${default_challengedir:?} +if [ -f "${__object:?}/parameter/challengedir" ]; +then + CHALLENGEDIR="$(cat "${__object:?}/parameter/challengedir")" +fi +export CHALLENGEDIR + +CONFDIR="${default_confdir:?}" +if [ -f "${__object:?}/parameter/confdir" ]; +then + CONFDIR="$(cat "${__object:?}/parameter/confdir")" +fi +export CONFDIR + +DISABLE_OCSP= +if [ -f "${__object:?}/parameter/no-ocsp" ]; +then + DISABLE_OCSP="--no-ocsp" +fi +export DISABLE_OCSP + +MAIN_DOMAIN=${__object_id:?} +DOMAIN=$MAIN_DOMAIN +if [ -f "${__object:?}/parameter/altdomains" ]; +then + # shellcheck disable=SC2013 + for altdomain in $(cat "${__object:?}/parameter/altdomains"); + do + DOMAIN="$DOMAIN $altdomain" + done +fi +export MAIN_DOMAIN DOMAIN + +HOOKSCRIPT=${default_hookscript} +if [ -f "${__object:?}/parameter/hookscript" ]; +then + HOOKSCRIPT="$(cat "${__object:?}/parameter/hookscript")" +fi +export HOOKSCRIPT + +KEYTYPE="-t EC" +if [ -f "${__object:?}/parameter/use-rsa" ]; +then + KEYTYPE="-t RSA" +fi +export KEYTYPE + +MUST_STAPLE= +if [ -f "${__object:?}/parameter/must-staple" ]; +then + MUST_STAPLE="--must-staple" +fi +export MUST_STAPLE + +# Non-default ACMEv2 server directory object URL. +ACME_URL= +if [ -f "${__object:?}/parameter/acme-url" ]; then + custom_acme_url=$(cat "${__object:?}/parameter/acme-url") + ACME_URL="--acme-url $custom_acme_url" +fi +export ACME_URL + +# Specify RFC8555 External Account Binding credentials. +EAB_CREDENTIALS= +if [ -f "${__object:?}/parameter/eab-credentials" ]; then + eab_credentials_param=$(cat "${__object:?}/parameter/eab-credentials") + EAB_CREDENTIALS="--eab $eab_credentials_param" +fi +export EAB_CREDENTIALS + +OWNER=root +if [ -f "${__object:?}/parameter/owner" ]; +then + OWNER="$(cat "${__object:?}/parameter/owner")" +fi +export OWNER + +KEY_TARGET= +if [ -f "${__object:?}/parameter/install-key-to" ]; +then + KEY_TARGET="$(cat "${__object:?}/parameter/install-key-to")" +fi +export KEY_TARGET + +CERT_TARGET= +if [ -f "${__object:?}/parameter/install-cert-to" ]; +then + CERT_TARGET="$(cat "${__object:?}/parameter/install-cert-to")" +fi +export CERT_TARGET + +RENEW_HOOK= +if [ -f "${__object:?}/parameter/renew-hook" ]; +then + if [ "$(cat "${__object:?}/parameter/renew-hook")" = "-" ]; then + RENEW_HOOK="$(cat ${__object:?}/stdin)" + else + RENEW_HOOK="$(cat "${__object:?}/parameter/renew-hook")" + fi +fi +export RENEW_HOOK + +if [ -n "$KEY_TARGET" ] && [ -z "$CERT_TARGET" ]; then + echo "You cannot specify --install-key-to without --install-cert-to." >&2 + exit 1 +elif [ -z "$KEY_TARGET" ] && [ -n "$CERT_TARGET" ]; then + echo "You cannot specify --install-cert-to without --install-key-to." >&2 + exit 1 +fi + +# Make sure challengedir exist. +__directory "$CHALLENGEDIR" --parents + +# Generate and deploy renew script. +mkdir -p "${__object:?}/files" +"${__type:?}/files/renew.sh.sh" > "${__object:?}/files/uacme-renew.sh" + +__directory "$CONFDIR/$MAIN_DOMAIN" +require="__directory/$CONFDIR/$MAIN_DOMAIN" __file "$CONFDIR/$MAIN_DOMAIN/renew.sh" \ + --mode 0755 --source "${__object:?}/files/uacme-renew.sh" + +# Set up renew cronjob - initial issue done in gencode-remote. +__cron "uacme-$MAIN_DOMAIN" --user root --hour 2 --minute 0 \ + --command "$CONFDIR/$MAIN_DOMAIN/renew.sh" diff --git a/type/__uacme_obtain/parameter/boolean b/type/__uacme_obtain/parameter/boolean new file mode 100644 index 0000000..44c04f4 --- /dev/null +++ b/type/__uacme_obtain/parameter/boolean @@ -0,0 +1,3 @@ +no-ocsp +must-staple +use-rsa diff --git a/type/__uacme_obtain/parameter/optional b/type/__uacme_obtain/parameter/optional new file mode 100644 index 0000000..9fa9846 --- /dev/null +++ b/type/__uacme_obtain/parameter/optional @@ -0,0 +1,9 @@ +challengedir +confdir +hookscript +owner +install-cert-to +install-key-to +renew-hook +acme-url +eab-credentials diff --git a/type/__uacme_obtain/parameter/optional_multiple b/type/__uacme_obtain/parameter/optional_multiple new file mode 100644 index 0000000..d3ebd88 --- /dev/null +++ b/type/__uacme_obtain/parameter/optional_multiple @@ -0,0 +1 @@ +altdomains diff --git a/type/__unbound/files/unbound.conf.sh b/type/__unbound/files/unbound.conf.sh new file mode 100755 index 0000000..4b0833c --- /dev/null +++ b/type/__unbound/files/unbound.conf.sh @@ -0,0 +1,84 @@ +#!/bin/sh -e +# Generates a configuration file for unbound(8). + +cat << EOF +# Configuration file for the ${__object_id:?} unbound(8) instance. +# Generated by cdist. DNE: your changes will be overwritten. +server: +EOF + +# Server logging +[ "$VERBOSITY" ] && printf "verbosity: %u\n" "$VERBOSITY" + +# IP version +[ "$DISABLE_IPV4" ] && echo "do-ip4: no" +[ "$DISABLE_IPV6" ] && echo "do-ip6: no" + +# Interfaces to bind to +[ "$PORT" ] && printf "port: %u\n" "$PORT" +if [ -f "${__object:?}/parameter/interface" ]; +then + while read -r intf; + do + printf "interface: %s\n" "$intf" + done < "${__object:?}/parameter/interface" +fi + +[ "$IP_TRANSPARENT" ] && printf "ip-transparent: yes\n" + +# Access control +if [ -f "${__object:?}/parameter/access-control" ]; +then + while read -r acl; + do + printf "access-control: %s\n" "$acl" + done < "${__object:?}/parameter/access-control" +fi + +# Local data +if [ -f "${__object:?}/parameter/local-data" ]; +then + while read -r data; + do + printf "local-data: \"%s\"\n" "$data" + done < "${__object:?}/parameter/local-data" +fi + +# DNS64 +printf "module-config: \"%svalidator iterator\"\n" "${DNS64:+dns64 }" +[ "$PREFIX64" ] && printf "dns64-prefix: %s\n" "$PREFIX64" + +# Remote control +echo "remote-control:" +[ "$ENABLE_RC" ] && echo "control-enable: yes" +[ "$CONTROL_PORT" ] && printf "control-port: %u\n" "$CONTROL_PORT" + +if [ "$CONTROL_USE_CERTS" ]; +then + printf "server-key-file: %s\n" "${RC_SERVER_KEY_FILE:?}" + printf "server-cert-file: %s\n" "${RC_SERVER_CERT_FILE:?}" + printf "control-key-file: %s\n" "${RC_CONTROL_KEY_FILE:?}" + printf "control-cert-file: %s\n" "${RC_CONTROL_CERT_FILE:?}" +fi + +if [ -f "${__object:?}/parameter/control-interface" ]; +then + while read -r acl; + do + printf "control-interface: %s\n" "$acl" + done < "${__object:?}/parameter/control-interface" +fi + +# Forwarding recursive queries +if [ -f "${__object:?}/parameter/forward-zone" ]; +then + while read -r fdzne + do + printf "forward-zone:\n" + printf "name: %s\n" "$(echo "$fdzne" | cut -f1 -d',')" + echo "$fdzne" | cut -f 2- -d',' | tr ',' '\n' | while read -r addr; + do + printf "forward-addr: %s\n" "$addr" + done + done < "${__object:?}/parameter/forward-zone"; +fi diff --git a/type/__unbound/gencode-remote b/type/__unbound/gencode-remote new file mode 100755 index 0000000..d8d5f1c --- /dev/null +++ b/type/__unbound/gencode-remote @@ -0,0 +1,21 @@ +#!/bin/sh + +if ! [ -f "${__object:?}/parameter/control-use-certs" ]; +then + exit 0; +fi + +UNBOUND_CERTS_DIR=/etc/unbound + +if [ -f "${__object:?}/parameter/enable-rc" ]; then + echo "unbound-control-setup -d $UNBOUND_CERTS_DIR" + echo "chown unbound:unbound $UNBOUND_CERTS_DIR/*.pem $UNBOUND_CERTS_DIR/*.key" +fi + +cat << EOF +if pgrep unbound; then + service ${__object_id:?} reload +else + service ${__object_id:?} start +fi +EOF diff --git a/type/__unbound/man.rst b/type/__unbound/man.rst new file mode 100644 index 0000000..f253564 --- /dev/null +++ b/type/__unbound/man.rst @@ -0,0 +1,126 @@ +cdist-type__unbound(7) +======================= + +NAME +---- +cdist-type__unbound - configure an instance of unbound, a DNS validating resolver. + + +DESCRIPTION +----------- +This type writes the configuration and OpenRC init scripts to run an instance +of unbound. The most commonly used options for unbound are configurable through +flags. + +Note that this type is currently only implemented (and tested) on Alpine Linux. +Please contribute other implementations if you can. + + +OPTIONAL PARAMETERS +------------------- +verbosity + Control the `unbound.conf(5)` verbosity parameter. + +port + Control the `unbound.conf(5)` port parameter. + +control-port + Control the `unbound.conf(5)` control-port parameter. + +dns64-prefix + Control the `unbound.conf(5)` dns64-prefix parameter. + +OPTIONAL MULTIPLE PARAMETERS +---------------------------- +interface + Control the `unbound.conf(5)` interface parameter. Can be + given multiple times, will generate multiple `interface: + xxx` clauses. + +access-control + Control the `unbound.conf(5)` access-control parameter. Can be given + multiple times, will generate multiple `access-control` clauses. The format + is an IP block followed by an access-control keyword. + +control-interface + Control the `unbound.conf(5)` control-interface parameter. Can be given + mutltiple times, will generate multiple `control-interface` clauses. Note + that without the `enable-rc` boolean flags, remote control will not be + enabled. Note that if at least one control interfaces is not a local socket, + then you should enable the `control-use-certs` boolean flag to generate and + configure TLS certificates for use between `unbound(8)` and + `unbound-control(8)` + +forward-zone + Define a forward zone. Each zone is comprised of a name, which defines for + what domains this zone applies, and at least one DNS server to which the + queries should be forwarded. The format is a comma-separated list of values + where the first element is the name of the zone, and the following elements + are the IP addresses of the DNS servers; e.g. `example.com,1.2.3.4,4.3.2.1` + +local-data + Control the `unbound.conf(5)` local-data parameter. Note that no local-zone + is defined, so the unbound default is to treat this data as a transparent + local zone. + +BOOLEAN PARAMETERS +------------------ +ip-transparent + Control the `unbound.conf(5)` ip-transparent parameter. + +dns64 + Enables the addition of the DNS64 module. + +enable-rc + Enable remote control. + +control-use-certs + Enable the generation using `unbound-control-setup(8)` of TLS certificates + for the interaction between `unbound(8)` and `unbound-control(8)`, as well as + their inclusion in the configuration file. + +disable-ip4 + Disable answering queries over IPv4. + +disable-ip6 + Disable answering queries over IPv6. + +EXAMPLES +-------- + +.. code-block:: sh + + # Setup two resolvers, one with dns64, the other without. + __unbound unbound \ + --dns64 \ + --ip-transparent \ + --interface "$address" \ + --access-control "$address/64 allow" \ + --enable-rc \ + --control-interface "/var/run/unbound_control.sock" + + __unbound unbound6only \ + --ip-transparent \ + --interface "$addresstwo" \ + --access-control "$addresstwo/64 allow" \ + --forward-zone "example.com,1.1.1.1,2.2.2.2" + + +SEE ALSO +-------- +`unbound(8)` +`unbound.conf(5)` +`unbound-control(8)` + + +AUTHORS +------- +Joachim Desroches + + +COPYING +------- +Copyright \(C) 2021 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__unbound/manifest b/type/__unbound/manifest new file mode 100755 index 0000000..917dbf0 --- /dev/null +++ b/type/__unbound/manifest @@ -0,0 +1,135 @@ +#!/bin/sh -xe +# +# 2020 Joachim Desroches (joachim.desroches@epfl.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + + +os=$(cat "${__global:?}/explorer/os") + +case "$os" in +alpine) + __package unbound + openssl_package=openssl + ;; +*) + printf "%s is currently not supported by __unbound\n" "$os" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +# Optional parameters: +if [ -f "${__object:?}/parameter/verbosity" ]; +then + VERBOSITY=$(cat "${__object:?}/parameter/verbosity") + export VERBOSITY +fi + +if [ -f "${__object:?}/parameter/port" ]; +then + PORT=$(cat "${__object:?}/parameter/port") + export PORT +fi + +if [ -f "${__object:?}/parameter/control-port" ]; +then + CONTROL_PORT=$(cat "${__object:?}/parameter/control-port") + export CONTROL_PORT +fi + +if [ -f "${__object:?}/parameter/dns64-prefix" ]; +then + PREFIX64=$(cat "${__object:?}/parameter/dns64-prefix") + export PREFIX64 +fi + +# Boolean parameters: +if [ -f "${__object:?}/parameter/ip-transparent" ]; +then + IP_TRANSPARENT=yes + export IP_TRANSPARENT +fi + +if [ -f "${__object:?}/parameter/dns64" ]; +then + DNS64=yes + export DNS64 +fi + +if [ -f "${__object:?}/parameter/enable-rc" ]; +then + ENABLE_RC=yes + export ENABLE_RC +fi + +if [ -f "${__object:?}/parameter/disable-ip4" ]; +then + DISABLE_IPV4=yes + export DISABLE_IPV4 +fi + +if [ -f "${__object:?}/parameter/disable-ip6" ]; +then + DISABLE_IPV6=yes + export DISABLE_IPV6 +fi + +if [ -f "${__object:?}/parameter/control-use-certs" ]; +then + __package "$openssl_package" + export CONTROL_USE_CERTS=yes +fi + +# Certs for remote control, generated if --generate-certs is given. +export RC_SERVER_KEY_FILE='/etc/unbound/unbound_server.key' +export RC_SERVER_CERT_FILE='/etc/unbound/unbound_server.pem' +export RC_CONTROL_KEY_FILE='/etc/unbound/unbound_control.key' +export RC_CONTROL_CERT_FILE='/etc/unbound/unbound_control.pem' + +export require='__package/unbound' +# If object_id is different from 'unbound', we consider that we are launching a +# different instance of unbound and create the appropriate init service. +if [ "${__object_id:?}" != "unbound" ]; +then + __link "/etc/init.d/${__object_id:?}" \ + --type symbolic --source /etc/init.d/unbound + + # The unbound init service checks the proper configuration file but does not + # specify to load it, so we add a daemon configuration file. + __file "/etc/conf.d/${__object_id:?}" \ + --owner root --mode 0600 --source - <<- EOF + # Generated by cdist. + command_args="-c /etc/unbound/\$RC_SVCNAME.conf" + EOF + + require="__link/etc/init.d/${__object_id:?}" \ + __start_on_boot "${__object_id:?}" +else + __start_on_boot unbound +fi +unset require + +# Generate and deploy configuration files. +source_file="${__object:?}/files/unbound.conf" +target_file="/etc/unbound/${__object_id:?}.conf" + +mkdir -p "$__object/files" +"${__type:?}/files/unbound.conf.sh" > "$source_file" +require="__package/unbound" __file "$target_file" \ + --source "$source_file" \ + --owner root --mode 644 diff --git a/type/__unbound/parameter/boolean b/type/__unbound/parameter/boolean new file mode 100644 index 0000000..9825db7 --- /dev/null +++ b/type/__unbound/parameter/boolean @@ -0,0 +1,6 @@ +ip-transparent +dns64 +enable-rc +control-use-certs +disable-ip4 +disable-ip6 diff --git a/type/__unbound/parameter/optional b/type/__unbound/parameter/optional new file mode 100644 index 0000000..26aa199 --- /dev/null +++ b/type/__unbound/parameter/optional @@ -0,0 +1,4 @@ +verbosity +port +control-port +dns64-prefix diff --git a/type/__unbound/parameter/optional_multiple b/type/__unbound/parameter/optional_multiple new file mode 100644 index 0000000..71816ca --- /dev/null +++ b/type/__unbound/parameter/optional_multiple @@ -0,0 +1,5 @@ +interface +access-control +control-interface +forward-zone +local-data diff --git a/type/__unbound_exporter/files/openrc-service b/type/__unbound_exporter/files/openrc-service new file mode 100644 index 0000000..6caed5e --- /dev/null +++ b/type/__unbound_exporter/files/openrc-service @@ -0,0 +1,12 @@ +#!/sbin/openrc-run + +name=$RC_SVCNAME +command="/usr/local/bin/unbound_exporter" +command_args="" +command_user="unbound" +command_background="yes" +pidfile="/var/run/$RC_SVCNAME.pid" + +depend() { + need unbound +} diff --git a/type/__unbound_exporter/gencode-remote b/type/__unbound_exporter/gencode-remote new file mode 100755 index 0000000..e360028 --- /dev/null +++ b/type/__unbound_exporter/gencode-remote @@ -0,0 +1,49 @@ +#!/bin/sh -e +# +# 2020 Timothée Floure (timothee.floure@ungleich.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . + +upstream=https://github.com/wish/unbound_exporter/archive +version=$(cat "$__object/parameter/version") +release="unbound_exporter-$version" + +cat << EOF +if command -v unbound_exporter +then + # already installed - ignoring. + echo "Nothing to do -" +else + # Initialize working directory + workdir=\$(mktemp -d) + cd \$workdir + + # Download and extract sources for requested release. + curl -L $upstream/v$version.tar.gz --output $release.tar.gz + tar xf $release.tar.gz + + # Build and install binary. + cd $release + go build + install -m755 unbound_exporter /usr/local/bin/ + + # Clean up! + rm -r \$workdir + + # Start service. + service unbound_exporter start +fi +EOF diff --git a/type/__unbound_exporter/man.rst b/type/__unbound_exporter/man.rst new file mode 100644 index 0000000..934bdd7 --- /dev/null +++ b/type/__unbound_exporter/man.rst @@ -0,0 +1,63 @@ +cdist-type__unbound_exporter(7) +=============================== + +NAME +---- +cdist-type__unbound_exporter - A prometheus exporter for unbound + + +DESCRIPTION +----------- +Simple Prometheus metrics exporter for the Unbound DNS +resolver. It leverages the unbound remote control endpoint +and exposes metrics on port 9167. + + +REQUIRED PARAMETERS +------------------- +version + unbound_exporter release to be used. + +OPTIONAL PARAMETERS +------------------- +None. + + +BOOLEAN PARAMETERS +------------------ +None. + + +EXAMPLES +-------- + +.. code-block:: sh + + __unbound \ + --interface '::0' \ + --forward_addr '2a0a:e5c0:2:1::5' \ + --forward_addr '2a0a:e5c0:2:1::6' \ + --access_control '::0/0 deny' \ + --access_control '2a0a:e5c0::/29 allow' \ + --access_control '2a09:2940::/29 allow' \ + --disable_ip4 \ + --enable_rc \ + --rc_interface '::1' + + __unbound_exporter --version 0.1.3 + +SEE ALSO +-------- +:strong:`cdist-type__unbound(7)` + +AUTHORS +------- +Timothée Floure + + +COPYING +------- +Copyright \(C) 2020 Timothée Floure. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__unbound_exporter/manifest b/type/__unbound_exporter/manifest new file mode 100755 index 0000000..7fa7df5 --- /dev/null +++ b/type/__unbound_exporter/manifest @@ -0,0 +1,44 @@ +#!/bin/sh -e +# +# 2020 Timothée Floure (timothee.floure@ungleich.ch) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + + +os=$(cat "$__global/explorer/os") + +case "$os" in + alpine) + # Used in gencode-remote. + __package curl + __package tar + __package openssl + __package go + __package libc-dev + ;; + *) + printf "Your operating system (%s) is currently not supported by this type (%s)\n" "$os" "${__type##*/}" >&2 + printf "Please contribute an implementation for it if you can.\n" >&2 + exit 1 + ;; +esac + +__file /etc/init.d/unbound_exporter \ + --source "$__type/files/openrc-service" \ + --mode 755 + +require="__file/etc/init.d/unbound_exporter" __start_on_boot unbound_exporter diff --git a/type/__unbound_exporter/parameter/required b/type/__unbound_exporter/parameter/required new file mode 100644 index 0000000..088eda4 --- /dev/null +++ b/type/__unbound_exporter/parameter/required @@ -0,0 +1 @@ +version diff --git a/type/__unbound_exporter/singleton b/type/__unbound_exporter/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__wikijs/files/config.yml.sh b/type/__wikijs/files/config.yml.sh new file mode 100755 index 0000000..b66687a --- /dev/null +++ b/type/__wikijs/files/config.yml.sh @@ -0,0 +1,46 @@ +#!/bin/sh + +if [ $# -ne 1 ]; +then + echo "You have to give me the database password as an argument:" + echo "on some systems, anyone can read env(1)." + exit 1; +fi + +generate_ssl_section () { + + cat << EOF +ssl: + enabled: ${SSL} +EOF + +if [ "$SSL" = "true" ]; then + cat << EOF + port: $HTTPS_PORT + provider: letsencrypt + domain: ${__target_host:?} + subscriberEmail: ${LE_EMAIL:?} +EOF + fi +} + +cat << EOF +port: $HTTP_PORT +db: + type: postgres + host: localhost + port: 5432 + user: ${DB_USER:?} + pass: $1 + db: ${DB_NAME:?} + ssl: false +$(generate_ssl_section) +pool: + min: 2 + max: 10 +bindIP: 0.0.0.0 +logLevel: warn +offline: false +ha: false +dataPath: ./data +EOF diff --git a/type/__wikijs/files/wikijs-openrc b/type/__wikijs/files/wikijs-openrc new file mode 100644 index 0000000..351332a --- /dev/null +++ b/type/__wikijs/files/wikijs-openrc @@ -0,0 +1,11 @@ +#!/sbin/openrc-run + +command='/usr/bin/node' +command_args='server' +command_background=true +command_user='wikijs' +description="Run wiki.js" +directory='/var/wiki' +error_log=/var/log/"$RC_SVCNAME".err +output_log=/var/log/"$RC_SVCNAME".log +pidfile="/run/$RC_SVCNAME.pid" diff --git a/type/__wikijs/gencode-remote b/type/__wikijs/gencode-remote new file mode 100755 index 0000000..3058fde --- /dev/null +++ b/type/__wikijs/gencode-remote @@ -0,0 +1,27 @@ +#!/bin/sh + +VERSION_FILE=/var/wiki/version +version=$(cat "${__object:?}/parameter/version") + +# Check for installation +cat << EOF +if [ -f $VERSION_FILE ] && [ "\$(cat $VERSION_FILE)" = "$version" ]; +then + # Assume everything is done already. + exit 0; +else + echo "$version" > $VERSION_FILE +fi +EOF + +# Download and copy source +cat << EOF +wget -O - https://github.com/Requarks/wiki/releases/download/$version/wiki-js.tar.gz | tar xz -C /var/wiki +chown -R wikijs:wikijs /var/wiki +EOF + +# Install deps and launch +cat << EOF +cd /var/wiki || exit 1 +service wikijs restart +EOF diff --git a/type/__wikijs/man.rst b/type/__wikijs/man.rst new file mode 100644 index 0000000..b259c90 --- /dev/null +++ b/type/__wikijs/man.rst @@ -0,0 +1,64 @@ +cdist-type__wikijs(7) +======================== + +NAME +---- +cdist-type__wikijs - Deploy the wiki.js software. + +DESCRIPTION +----------- + +See wiki.js.org for more information. This type deploys with a postgresql +database, since it is the upstream recommended for production, and they seem to +strongly suggest that in the next releases, they will not support anything else. + +Currently, this type servers wikijs as standalone, listening on ports 80 and +443, and with a service file for OpenRC. Feel free to contribute a +generalisation if you require one. + +REQUIRED PARAMETERS +------------------- + +database-password + The password to the PSQL database. + +version + 'wikijs' version to be deployed. + +OPTIONAL PARAMETERS +------------------- + +database + The name of the PSQL database to connect to. If omitted, then 'wikijs' is + used. + +database-user + The name of the PSQL database user to connec as. If omitted, then 'wikijs' is + used. + +letsencrypt-mail + If the SSL parameter is passed, then we setup wikijs to automatically obtain + certificates: this is the email used to sign up to a LE account. + +http-port + Specify HTTP port, defaults to 80. + +http-port + Specify HTTPS port, defaults to 443. Only relevant if the SSL flag is enabled. + +BOOLEAN PARAMETERS +------------------ + +ssl + Whether or not to enable the wikijs automatic obtention of LE certificates. + +AUTHORS +------- +Joachim Desroches + +COPYING +------- +Copyright \(C) 2020 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__wikijs/manifest b/type/__wikijs/manifest new file mode 100644 index 0000000..8231ebb --- /dev/null +++ b/type/__wikijs/manifest @@ -0,0 +1,71 @@ +#!/bin/sh + +os="$(cat "${__global:?}"/explorer/os)" + +case "$os" in + alpine) + : + ;; + *) + echo "This type has no implementation for $os. Aborting." >&2; + exit 1; +esac + +DB_USER=wikijs +if [ -f "${__object:?}/parameter/database-user" ]; +then + DB_USER="$(cat "${__object:?}/parameter/database-user")" +fi +export DB_USER + +DB_NAME=wikijs +if [ -f "${__object:?}/parameter/database" ]; +then + DB_NAME="$(cat "${__object:?}/parameter/database")" +fi +export DB_NAME + +SSL=false +if [ -f "${__object:?}/parameter/ssl" ]; +then + SSL=true +fi +export SSL + +if [ "$SSL" = "true" ]; +then + if [ -f "${__object:?}/parameter/letsencrypt-mail" ]; + then + LE_EMAIL="$(cat "${__object:?}/parameter/letsencrypt-mail")" + export LE_EMAIL + else + echo "You must specify an email account if you request SSL." + echo "Hit me." + exit 1 + fi +fi + +HTTP_PORT=$(cat "${__object:?}/parameter/http-port") +HTTPS_PORT=$(cat "${__object:?}/parameter/https-port") +export HTTP_PORT HTTPS_PORT + +db_pass="$(cat "${__object:?}/parameter/database-password")" + +__package nodejs +__user wikijs --home /var/wiki --create-home + +# These things are Alpine-dependant. +__file /etc/init.d/wikijs \ + --source "${__type:?}/files/wikijs-openrc" \ + --mode 0755 +__package nghttp2-dev # Required for some reason, else a symbol is missing +for logfile in wikijs.log wikijs.err; do + require="__user/wikijs" __file /var/log/$logfile --owner wikijs +done + +mkdir -p "${__object:?}/files" +"${__type:?}/files/config.yml.sh" "$db_pass" > "${__object:?}/files/config.yml" +require='__user/wikijs' \ + __file /var/wiki/config.yml \ + --source "${__object:?}/files/config.yml" \ + --owner wikijs diff --git a/type/__wikijs/parameter/boolean b/type/__wikijs/parameter/boolean new file mode 100644 index 0000000..a2647ce --- /dev/null +++ b/type/__wikijs/parameter/boolean @@ -0,0 +1 @@ +ssl diff --git a/type/__wikijs/parameter/default/http-port b/type/__wikijs/parameter/default/http-port new file mode 100644 index 0000000..d15a2cc --- /dev/null +++ b/type/__wikijs/parameter/default/http-port @@ -0,0 +1 @@ +80 diff --git a/type/__wikijs/parameter/default/https-port b/type/__wikijs/parameter/default/https-port new file mode 100644 index 0000000..6a13cf6 --- /dev/null +++ b/type/__wikijs/parameter/default/https-port @@ -0,0 +1 @@ +443 diff --git a/type/__wikijs/parameter/optional b/type/__wikijs/parameter/optional new file mode 100644 index 0000000..be19c92 --- /dev/null +++ b/type/__wikijs/parameter/optional @@ -0,0 +1,5 @@ +database +database-user +letsencrypt-mail +http-port +https-port diff --git a/type/__wikijs/parameter/required b/type/__wikijs/parameter/required new file mode 100644 index 0000000..ae542bc --- /dev/null +++ b/type/__wikijs/parameter/required @@ -0,0 +1,2 @@ +database-password +version diff --git a/type/__wikijs/singleton b/type/__wikijs/singleton new file mode 100644 index 0000000..e69de29 diff --git a/type/__wireguard/files/interface.conf.sh b/type/__wireguard/files/interface.conf.sh new file mode 100755 index 0000000..e6b7e82 --- /dev/null +++ b/type/__wireguard/files/interface.conf.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +cat <<- EOF + auto ${WG_IFACE:?} + iface ${WG_IFACE:?} inet6 static + address ${WG_ADDRESS:?} + pre-up ip link add dev ${WG_IFACE:?} type wireguard + pre-up wg setconf ${WG_IFACE:?} /etc/wireguard/${WG_IFACE:?}.conf + post-down ip link delete dev ${WG_IFACE:?} +EOF diff --git a/type/__wireguard/files/wireguard.conf.sh b/type/__wireguard/files/wireguard.conf.sh new file mode 100755 index 0000000..2712d07 --- /dev/null +++ b/type/__wireguard/files/wireguard.conf.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +if [ $# -ne 1 ]; +then + echo "The WG private key must be passed to the script as an argument," >&2 + echo "as we do not consider the environment to be private. Aborting." >&2 + exit 1; +fi + +cat <<- EOF + [Interface] + PrivateKey = ${1:?} +EOF + +if [ -n "$WG_PORT" ]; +then + echo "ListenPort = ${WG_PORT:?}" +fi diff --git a/type/__wireguard/gencode-remote b/type/__wireguard/gencode-remote new file mode 100644 index 0000000..7a06fb4 --- /dev/null +++ b/type/__wireguard/gencode-remote @@ -0,0 +1,8 @@ +#!/bin/sh + +if grep -q "^__block/${__object_id:?}" "${__messages_in:?}"; then + cat <<- EOF + wg syncconf ${__object_id:?} /etc/wireguard/${__object_id:?}.conf + EOF +fi + diff --git a/type/__wireguard/man.rst b/type/__wireguard/man.rst new file mode 100644 index 0000000..ef08f12 --- /dev/null +++ b/type/__wireguard/man.rst @@ -0,0 +1,53 @@ +cdist-type__wireguard(7) +======================== + +NAME +---- +cdist-type__wireguard - Configure a wireguard interface + +DESCRIPTION +----------- + +This type creates a wireguard interface named using the `${__object_id}`. It +generates a configuration file for wireguard and a configuration file for +ifconfig, and then brings the interface up. + +Additional peers for the created wireguard interface can be added using +`cdist-type__wireguard_peers(7)`. + +Currently, this type is only implemented for Alpine Linux. + +Currently, this type only supports setting an IPv6 address to assign to the +wireguard interface. + +REQUIRED PARAMETERS +------------------- + +privkey + The private key for this wireguard instance. + +address + The IPv6 address to assign to the wireguard interface, optionally with a CIDR + mask. + +OPTIONAL PARAMETERS +------------------- + +port + The port to listen on. If not specified, wireguard will choose one randomly. + +SEE ALSO +-------- + +`wg(8)`, `wg-quick(8)`, `cdist-type__wireguard(7)`, `cdist-type__block(7)` + +AUTHORS +------- +Joachim Desroches + +COPYING +------- +Copyright \(C) 2020 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__wireguard/manifest b/type/__wireguard/manifest new file mode 100644 index 0000000..1b977de --- /dev/null +++ b/type/__wireguard/manifest @@ -0,0 +1,56 @@ +#!/bin/sh + +os="$(cat "${__global:?}"/explorer/os)" + +case $os in + 'alpine') + : + ;; + *) + echo "This type has no implementation for $os. Aborting." >&2 + exit 1; + ;; +esac + +__package "wireguard-tools-wg" + +# Template configuration +private_key="$(cat "${__object:?}/parameter/privkey")" + +WG_ADDRESS="$(cat "${__object:?}/parameter/address")" +WG_IFACE="${__object_id:?}" + +export WG_IFACE +export WG_ADDRESS + +WG_PORT= +if [ -f "${__object:?}/parameter/port" ]; +then + WG_PORT="$(cat "${__object:?}/parameter/port")" +fi +export WG_PORT + +mkdir -p "${__object:?}/files/" +"${__type:?}/files/wireguard.conf.sh" "$private_key" > "${__object:?}/files/wg-${__object_id:?}.conf" + +# Wireguard configuration. Configured using a block as it is also edited by +# cdist-type__wireguard_peer(7). +__directory "/etc/wireguard/" +require='__directory/etc/wireguard' \ + __file "/etc/wireguard/${__object_id:?}.conf" --state exists + +require="__file/etc/wireguard/${__object_id:?}.conf" \ + __block "${__object_id:?}" --file "/etc/wireguard/${__object_id:?}.conf" \ + --text - <"${__object:?}/files/wg-${__object_id:?}.conf" + +# Network configuration +__directory '/etc/network/interfaces.d' +__line source-interfaces \ + --line 'source-directory /etc/network/interfaces.d/' \ + --file '/etc/network/interfaces' + +"${__type:?}/files/interface.conf.sh" > "${__object:?}/files/iif-${__object_id:?}.conf" +require="__directory/etc/network/interfaces.d __line/source-interfaces __block/${__object_id:?}" \ + __file "/etc/network/interfaces.d/${__object_id:?}.conf" \ + --source "${__object:?}/files/iif-${__object_id:?}.conf" \ + --onchange "ifup -a" diff --git a/type/__wireguard/parameter/optional b/type/__wireguard/parameter/optional new file mode 100644 index 0000000..20e6f14 --- /dev/null +++ b/type/__wireguard/parameter/optional @@ -0,0 +1 @@ +port diff --git a/type/__wireguard/parameter/required b/type/__wireguard/parameter/required new file mode 100644 index 0000000..753d5ce --- /dev/null +++ b/type/__wireguard/parameter/required @@ -0,0 +1,2 @@ +address +privkey diff --git a/type/__wireguard_peer/files/wg-peer.sh b/type/__wireguard_peer/files/wg-peer.sh new file mode 100755 index 0000000..ac30f07 --- /dev/null +++ b/type/__wireguard_peer/files/wg-peer.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# We expect the pre-shared key, if it exists, as an argument because we do not +# consider the environment to be secure. + +cat << EOF +[Peer] +PublicKey = ${PKEY:?} +EOF + +if [ -n "$1" ]; +then + echo "PresharedKey = ${1:?}" +fi + +for ip in $ALLOWED_IPS; +do + echo "AllowedIPs = ${ip:?}" +done + +if [ -n "$ENDPOINT" ]; +then + echo "Endpoint = ${ENDPOINT:?}" +fi + +if [ -n "$PERSISTENT_KA" ]; +then + echo "PersistentKeepalive = ${PERSISTENT_KA:?}" +fi + +echo diff --git a/type/__wireguard_peer/gencode-remote b/type/__wireguard_peer/gencode-remote new file mode 100644 index 0000000..92c80c6 --- /dev/null +++ b/type/__wireguard_peer/gencode-remote @@ -0,0 +1,10 @@ +#!/bin/sh + +iface="$(cat "${__object:?}/parameter/iface")" + +if grep -q "^__block/${__object_id:?}" "${__messages_in:?}"; +then + cat <<- EOF + wg syncconf ${iface:?} /etc/wireguard/${iface:?}.conf + EOF +fi diff --git a/type/__wireguard_peer/man.rst b/type/__wireguard_peer/man.rst new file mode 100644 index 0000000..f0d1712 --- /dev/null +++ b/type/__wireguard_peer/man.rst @@ -0,0 +1,70 @@ +cdist-type__wiregurad_peer(7) +============================= + +NAME +---- +cdist-type__wiregurad_peer - Add an authorized peer to a wireguard interface. + +DESCRIPTION +----------- + +This type configures a peer to be authorized on a wireguard interface. The +`${__object_id}` is used to differentiate the `cdist-type__block(7)` where each peer is +defined. See `wg(8)` for details on the options. + +Note that this type **requires** a configuration file named after the `iface` +parameter to add and remove the peers from. The recommended way to accomplish +this is to call `cdist-type__wireguard(7)`, and set it as a requirement for +calls to this type adding peers to that interface. + +Currently, this type is only implemented for Alpine Linux. + +REQUIRED PARAMETERS +------------------- + +iface + The name of the wireguard interface to add the peer to. + +public-key + The peer's public key. + +OPTIONAL PARAMETERS +------------------- + +endpoint + The endpoint for this peer. + +persistent-keepalive + Send a keepalive packet every n seconds, expects an integer. + +preshared-key + A pre-shared symmetric key. Used for "post-quantum resistance". + +state + Directly passed on the `cdist-type__block(7)`, to enable removing a user. + +OPTIONAL MULTIPLE PARAMETERS +---------------------------- + +allowed-ip + A comma-separated list of IP (v4 or v6) addresses with CIDR masks from which + incoming traffic for this peer is allowed and to which outgoing traffic + for this peer is directed. The catch-all 0.0.0.0/0 may be specified for + matching all IPv4 addresses, and ::/0 may be specified for matching all IPv6 + addresses. + +SEE ALSO +-------- + +`wg(8)`, `wg-quick(8)`, `cdist-type__wireguard(7)`, `cdist-type__block(7)` + +AUTHORS +------- +Joachim Desroches + +COPYING +------- +Copyright \(C) 2020 Joachim Desroches. You can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation, either version 3 of the +License, or (at your option) any later version. diff --git a/type/__wireguard_peer/manifest b/type/__wireguard_peer/manifest new file mode 100644 index 0000000..c5584a9 --- /dev/null +++ b/type/__wireguard_peer/manifest @@ -0,0 +1,60 @@ +#!/bin/sh +# expected to be run with a required='__wireguard/ifname' + +os="$(cat "${__global:?}"/explorer/os)" + +case "$os" in + alpine) + : + ;; + *) + echo "This type has no implementation for $os. Aborting." >&2; + exit 1; +esac + +iface="$(cat "${__object:?}/parameter/iface")" + +PKEY="$(cat "${__object:?}/parameter/public-key")" +export PKEY + +ALLOWED_IPS= +if [ -f "${__object:?}/parameter/allowed-ip" ]; +then + ALLOWED_IPS="$(cat "${__object:?}/parameter/allowed-ip")" +fi +export ALLOWED_IPS + +ENDPOINT= +if [ -f "${__object:?}/parameter/endpoint" ]; +then + ENDPOINT="$(cat "${__object:?}/parameter/endpoint")" +fi +export ENDPOINT + +PERSISTENT_KA= +if [ -f "${__object:?}/parameter/persistent-keepalive" ]; +then + PERSISTENT_KA="$(cat "${__object:?}/parameter/persistent-keepalive")" +fi +export PERSISTENT_KA + +state=present +if [ -f "${__object:?}/parameter/state" ]; +then + state="$(cat "${__object:?}/parameter/state")" +fi + +presharedkey= +if [ -f "${__object:?}/parameter/preshared-key" ]; +then + presharedkey="$(cat "${__object:?}/parameter/preshared-key")" +fi + + +mkdir -p "${__object:?}/files" +"${__type:?}/files/wg-peer.sh" "$presharedkey" > "${__object:?}/files/wg-peer" + +required="__file/etc/wireguard/$iface.conf" \ + __block "${__object_id:?}" --file "/etc/wireguard/$iface.conf" \ + --text - <"${__object:?}/files/wg-peer" \ + --state "$state" diff --git a/type/__wireguard_peer/parameter/optional b/type/__wireguard_peer/parameter/optional new file mode 100644 index 0000000..ae643b1 --- /dev/null +++ b/type/__wireguard_peer/parameter/optional @@ -0,0 +1,4 @@ +endpoint +persistent-keepalive +preshared-key +state diff --git a/type/__wireguard_peer/parameter/optional_multiple b/type/__wireguard_peer/parameter/optional_multiple new file mode 100644 index 0000000..f6477ad --- /dev/null +++ b/type/__wireguard_peer/parameter/optional_multiple @@ -0,0 +1 @@ +allowed-ip diff --git a/type/__wireguard_peer/parameter/required b/type/__wireguard_peer/parameter/required new file mode 100644 index 0000000..9bfa644 --- /dev/null +++ b/type/__wireguard_peer/parameter/required @@ -0,0 +1,2 @@ +iface +public-key