diff --git a/.compose/chat/config.json b/.compose/chat/config.json new file mode 100644 index 00000000..13a49603 --- /dev/null +++ b/.compose/chat/config.json @@ -0,0 +1,17 @@ +{ + "application_name": "Twake Chat", + "application_welcome_message": "Welcome to Twake Chat!", + "default_homeserver": "docker.localhost", + "privacy_url": "https://twake.app/en/privacy/", + "render_html": true, + "hide_redacted_events": false, + "hide_unknown_events": false, + "issue_id": "", + "app_grid_dashboard_available": false, + "homeserver": "https://matrix.docker.localhost/", + "platform": "localDebug", + "default_max_upload_avatar_size_in_bytes": 1000000, + "dev_mode": true, + "enable_logs": true, + "support_url": "https://twake.app/support" +} diff --git a/.compose/chat/default.conf.template b/.compose/chat/default.conf.template new file mode 100644 index 00000000..bf0f6f80 --- /dev/null +++ b/.compose/chat/default.conf.template @@ -0,0 +1,14 @@ +server { + listen ${TWAKECHAT_LISTEN_PORT} default; + listen [::]:${TWAKECHAT_LISTEN_PORT} default; + + location = / { + return 301 https://chat.docker.localhost${TWAKECHAT_BASE_HREF}; + } + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $uri $uri/ /index.html; + } +} diff --git a/.compose/haproxy/cors.lua b/.compose/haproxy/cors.lua new file mode 100644 index 00000000..a1a22498 --- /dev/null +++ b/.compose/haproxy/cors.lua @@ -0,0 +1,247 @@ +-- +-- Cross-origin Request Sharing (CORS) implementation for HAProxy Lua host +-- +-- CORS RFC: +-- https://www.w3.org/TR/cors/ +-- +-- Copyright (c) 2019. Nick Ramirez +-- Copyright (c) 2019. HAProxy Technologies, LLC. + +local M={} + +-- Loops through array to find the given string. +-- items: array of strings +-- test_str: string to search for +function contains(items, test_str) + for _,item in pairs(items) do + if item == test_str then + return true + end + end + + return false +end + +M.wildcard_origin_allowed = function(allowed_origins) + if contains(allowed_origins, "*") then + return "*" + end + return nil +end + +M.specifies_scheme = function(s) + return string.find(s, "^%a+://") ~= nil +end + +M.specifies_generic_scheme = function(s) + return string.find(s, "^//") ~= nil +end + +M.begins_with_dot = function(s) + return string.find(s, "^%.") ~= nil +end + +M.trim = function(s) + return s:gsub("%s+", "") +end + +M.build_pattern = function(pattern) + -- remove spaces + pattern = M.trim(pattern) + + if pattern ~= nil and pattern ~= '' then + -- if there is no scheme and the pattern does not begin with a dot, + -- add the generic scheme to the beginning of the pattern + if M.specifies_scheme(pattern) == false and M.specifies_generic_scheme(pattern) == false and M.begins_with_dot(pattern) == false then + pattern = "//" .. pattern + end + + -- escape dots and dashes in pattern + pattern = pattern:gsub("([%.%-])", "%%%1") + + -- an asterisk for the port means allow all ports + if string.find(pattern, "[:]+%*$") ~= nil then + pattern = pattern:gsub("[:]+%*$", "[:]+[0-9]+") + end + + -- append end character + pattern = pattern .. "$" + return pattern + end + + return nil +end + +-- If the given origin is found within the allowed_origins string, it is returned. Otherwise, nil is returned. +-- origin: The value from the 'origin' request header +-- allowed_origins: Comma-delimited list of allowed origins. (e.g. localhost,https://localhost:8080,//test.com) +-- e.g. localhost : allow http(s)://localhost +-- e.g. //localhost : allow http(s)://localhost +-- e.g. https://mydomain.com : allow only HTTPS of mydomain.com +-- e.g. http://mydomain.com : allow only HTTP of mydomain.com +-- e.g. http://mydomain.com:8080 : allow only HTTP of mydomain.com from port 8080 +-- e.g. //mydomain.com : allow only http(s)://mydomain.com +-- e.g. .mydomain.com : allow ALL subdomains of mydomain.com from ALL source ports +-- e.g. .mydomain.com:443 : allow ALL subdomains of mydomain.com from default HTTPS source port +-- +-- e.g. ".mydomain.com:443, //mydomain.com:443, //localhost" +-- allows all subdomains and main domain of mydomain.com only for HTTPS from default HTTPS port and allows +-- all HTTP and HTTPS connections from ALL source port for localhost +-- +M.get_allowed_origin = function(origin, allowed_origins) + if origin ~= nil then + -- if wildcard (*) is allowed, return it, which allows all origins + wildcard_origin = M.wildcard_origin_allowed(allowed_origins) + if wildcard_origin ~= nil then + return wildcard_origin + end + + for index, allowed_origin in ipairs(allowed_origins) do + pattern = M.build_pattern(allowed_origin) + + if pattern ~= nil then + if origin:match(pattern) then + core.Debug("Test: " .. pattern .. ", Origin: " .. origin .. ", Match: yes") + return origin + else + core.Debug("Test: " .. pattern .. ", Origin: " .. origin .. ", Match: no") + end + end + end + end + + return nil +end + +-- Adds headers for CORS preflight request and then attaches them to the response +-- after it comes back from the server. This works with versions of HAProxy prior to 2.2. +-- The downside is that the OPTIONS request must be sent to the backend server first and can't +-- be intercepted and returned immediately. +-- txn: The current transaction object that gives access to response properties +-- allowed_methods: Comma-delimited list of allowed HTTP methods. (e.g. GET,POST,PUT,DELETE) +-- allowed_headers: Comma-delimited list of allowed headers. (e.g. X-Header1,X-Header2) +function preflight_request_ver1(txn, allowed_methods, allowed_headers) + core.Debug("CORS: preflight request received") + txn.http:res_set_header("Access-Control-Allow-Methods", allowed_methods) + txn.http:res_set_header("Access-Control-Allow-Headers", allowed_headers) + txn.http:res_set_header("Access-Control-Max-Age", 600) + core.Debug("CORS: attaching allowed methods to response") +end + +-- Add headers for CORS preflight request and then returns a 204 response. +-- The 'reply' function used here is available in HAProxy 2.2+. It allows HAProxy to return +-- a reply without contacting the server. +-- txn: The current transaction object that gives access to response properties +-- origin: The value from the 'origin' request header +-- allowed_methods: Comma-delimited list of allowed HTTP methods. (e.g. GET,POST,PUT,DELETE) +-- allowed_origins: Comma-delimited list of allowed origins. (e.g. localhost,localhost:8080,test.com) +-- allowed_headers: Comma-delimited list of allowed headers. (e.g. X-Header1,X-Header2) +function preflight_request_ver2(txn, origin, allowed_methods, allowed_origins, allowed_headers) + core.Debug("CORS: preflight request received") + + local reply = txn:reply() + reply:set_status(204, "No Content") + reply:add_header("Content-Type", "text/html") + reply:add_header("Access-Control-Allow-Methods", allowed_methods) + reply:add_header("Access-Control-Allow-Headers", allowed_headers) + reply:add_header("Access-Control-Max-Age", 600) + + local allowed_origin = M.get_allowed_origin(origin, allowed_origins) + + if allowed_origin == nil then + core.Debug("CORS: " .. origin .. " not allowed") + else + core.Debug("CORS: " .. origin .. " allowed") + reply:add_header("Access-Control-Allow-Origin", allowed_origin) + + if allowed_origin ~= "*" then + reply:add_header("Vary", "Accept-Encoding,Origin") + end + end + + core.Debug("CORS: Returning reply to preflight request") + txn:done(reply) +end + +-- When invoked during a request, captures the origin header if present and stores it in a private variable. +-- If the request is OPTIONS and it is a supported version of HAProxy, returns a preflight request reply. +-- Otherwise, the preflight request header is added to the response after it has returned from the server. +-- txn: The current transaction object that gives access to response properties +-- allowed_methods: Comma-delimited list of allowed HTTP methods. (e.g. GET,POST,PUT,DELETE) +-- allowed_origins: Comma-delimited list of allowed origins. (e.g. localhost,localhost:8080,test.com) +-- allowed_headers: Comma-delimited list of allowed headers. (e.g. X-Header1,X-Header2) +function cors_request(txn, allowed_methods, allowed_origins, allowed_headers) + local headers = txn.http:req_get_headers() + local transaction_data = {} + local origin = nil + local allowed_origins = core.tokenize(allowed_origins, ",") + + if headers["origin"] ~= nil and headers["origin"][0] ~= nil then + core.Debug("CORS: Got 'Origin' header: " .. headers["origin"][0]) + origin = headers["origin"][0] + end + + -- Bail if client did not send an Origin + -- for example, it may be a regular OPTIONS request that is not a CORS preflight request + if origin == nil or origin == '' then + return + end + + transaction_data["origin"] = origin + transaction_data["allowed_methods"] = allowed_methods + transaction_data["allowed_origins"] = allowed_origins + transaction_data["allowed_headers"] = allowed_headers + + txn:set_priv(transaction_data) + + local method = txn.sf:method() + transaction_data["method"] = method + + if method == "OPTIONS" and txn.reply ~= nil then + preflight_request_ver2(txn, origin, allowed_methods, allowed_origins, allowed_headers) + end +end + +-- When invoked during a response, sets CORS headers so that the browser can read the response from permitted domains. +-- txn: The current transaction object that gives access to response properties. +function cors_response(txn) + local transaction_data = txn:get_priv() + + if transaction_data == nil then + return + end + + local origin = transaction_data["origin"] + local allowed_origins = transaction_data["allowed_origins"] + local allowed_methods = transaction_data["allowed_methods"] + local allowed_headers = transaction_data["allowed_headers"] + local method = transaction_data["method"] + + -- Bail if client did not send an Origin + if origin == nil or origin == '' then + return + end + + local allowed_origin = M.get_allowed_origin(origin, allowed_origins) + + if allowed_origin == nil then + core.Debug("CORS: " .. origin .. " not allowed") + else + if method == "OPTIONS" and txn.reply == nil then + preflight_request_ver1(txn, allowed_methods, allowed_headers) + end + + core.Debug("CORS: " .. origin .. " allowed") + txn.http:res_set_header("Access-Control-Allow-Origin", allowed_origin) + + if allowed_origin ~= "*" then + txn.http:res_add_header("Vary", "Accept-Encoding,Origin") + end + end +end + +-- Register the actions with HAProxy +core.register_action("cors", {"http-req"}, cors_request, 3) +core.register_action("cors", {"http-res"}, cors_response, 0) + +return M diff --git a/.compose/haproxy/haproxy.cfg b/.compose/haproxy/haproxy.cfg new file mode 100644 index 00000000..f1732d8c --- /dev/null +++ b/.compose/haproxy/haproxy.cfg @@ -0,0 +1,68 @@ +global + user haproxy + group haproxy + # lua-load /usr/local/etc/haproxy/synapse_worker_endpoint_indexer.lua + lua-load /usr/local/etc/haproxy/cors.lua + log stdout format raw local0 + +defaults + log global + mode http + option httplog clf + option dontlognull + retries 3 + option redispatch + maxconn 2000 + +frontend http-in + bind *:443 ssl crt /etc/ssl/certs/both.pem + http-request lua.cors "GET,PUT,POST,DELETE" "*" "*" + http-response lua.cors + + acl is_matrix hdr_end(host) -i matrix.docker.localhost + acl is_synapse_matrix path_beg -i /_matrix + acl is_synapse_synapse path_beg -i /_synapse + acl is_well-known path_beg -i /.well-known/matrix + # If asking a synapse endpoint + #use_backend %[lua.path_to_worker] if is_matrix is_synapse_matrix || is_matrix is_synapse_synapse + # If not a /_matrix/ call, redirect to main worker + use_backend matrix if is_matrix + + acl is_tom hdr_end(host) -i tom.docker.localhost + acl is_tom path_beg -i /_twake + use_backend tom if is_tom + # If it's asking for the well_known endpoint + use_backend tom if is_matrix is_well-known + + acl is_chat hdr_end(host) -i chat.docker.localhost + use_backend chat if is_chat + + acl is_portal hdr_end(host) -i docker.localhost + acl is_portal hdr_end(host) -i auth.docker.localhost + use_backend portal if is_portal + +backend portal + balance roundrobin + option forwardfor + http-request set-header X-Forwarded-Proto https + server node1 auth:80 check + server node2 auth:80 check + server node3 auth:80 check + +backend matrix + balance roundrobin + option forwardfor + http-request set-header X-Forwarded-Proto https + server synapse_main synapse:8008 check + +backend tom + balance roundrobin + option forwardfor + http-request set-header X-Forwarded-Proto https + server node1 tom.server:3000 check + +backend chat + balance roundrobin + option forwardfor + http-request set-header X-Forwarded-Proto https + server node1 chat:6868 check diff --git a/.compose/haproxy/lua_endpoint_to_function.map_rewrite.cfg b/.compose/haproxy/lua_endpoint_to_function.map_rewrite.cfg new file mode 100644 index 00000000..5ccfd02b --- /dev/null +++ b/.compose/haproxy/lua_endpoint_to_function.map_rewrite.cfg @@ -0,0 +1,129 @@ +# Sync requests +^/_matrix/client/(r0|v3)/sync$ synchrotron +^/_matrix/client/(api/v1|r0|v3)/events$ synchrotron +^/_matrix/client/(api/v1|r0|v3)/initialSync$ synchrotron +^/_matrix/client/(api/v1|r0|v3)/rooms/[^/]+/initialSync$ synchrotron + +# Federation requests +^/_matrix/federation/v1/event/ federation_reader +^/_matrix/federation/v1/state/ federation_reader +^/_matrix/federation/v1/state_ids/ federation_reader +^/_matrix/federation/v1/backfill/ federation_reader +^/_matrix/federation/v1/get_missing_events/ federation_reader +^/_matrix/federation/v1/publicRooms federation_reader +^/_matrix/federation/v1/query/ federation_reader +^/_matrix/federation/v1/make_join/ federation_reader +^/_matrix/federation/v1/make_leave/ federation_reader +^/_matrix/federation/(v1|v2)/send_join/ federation_reader +^/_matrix/federation/(v1|v2)/send_leave/ federation_reader +^/_matrix/federation/(v1|v2)/invite/ federation_reader +^/_matrix/federation/v1/event_auth/ federation_reader +^/_matrix/federation/v1/timestamp_to_event/ federation_reader +^/_matrix/federation/v1/exchange_third_party_invite/ federation_reader +^/_matrix/federation/v1/user/devices/ federation_reader +^/_matrix/key/v2/query federation_reader +^/_matrix/federation/v1/hierarchy/ federation_reader + +# Inbound federation transaction request +^/_matrix/federation/v1/send/ federation_inbound + +# Client API requests +^/_matrix/client/(api/v1|r0|v3|unstable)/createRoom$ client +^/_matrix/client/(api/v1|r0|v3|unstable)/publicRooms$ client +^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/joined_members$ client +^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/context/.*$ client +^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/members$ client +^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/state$ client +^/_matrix/client/v1/rooms/.*/hierarchy$ client +^/_matrix/client/(v1|unstable)/rooms/.*/relations/ client +^/_matrix/client/v1/rooms/.*/threads$ client +^/_matrix/client/unstable/im.nheko.summary/rooms/.*/summary$ client +^/_matrix/client/(r0|v3|unstable)/account/3pid$ client +^/_matrix/client/(r0|v3|unstable)/account/whoami$ client +^/_matrix/client/(r0|v3|unstable)/devices$ client +^/_matrix/client/versions$ client +^/_matrix/client/(api/v1|r0|v3|unstable)/voip/turnServer$ client +^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/event/ client +^/_matrix/client/(api/v1|r0|v3|unstable)/joined_rooms$ client +^/_matrix/client/v1/rooms/.*/timestamp_to_event$ client +^/_matrix/client/(api/v1|r0|v3|unstable/.*)/rooms/.*/aliases client +^/_matrix/client/(api/v1|r0|v3|unstable)/search$ client +^/_matrix/client/(r0|v3|unstable)/user/.*/filter(/|$) client +^/_matrix/client/(api/v1|r0|v3|unstable)/directory/room/.*$ client +^/_matrix/client/(r0|v3|unstable)/capabilities$ client + +# Encryption requests +^/_matrix/client/(r0|v3|unstable)/keys/query$ encryption +^/_matrix/client/(r0|v3|unstable)/keys/changes$ encryption +^/_matrix/client/(r0|v3|unstable)/keys/claim$ encryption +^/_matrix/client/(r0|v3|unstable)/room_keys/ encryption +^/_matrix/client/(r0|v3|unstable)/keys/upload/ encryption + +# Registration/login requests +^/_matrix/client/(api/v1|r0|v3|unstable)/login$ registration +^/_matrix/client/(r0|v3|unstable)/register$ registration +^/_matrix/client/(r0|v3|unstable)/register/available$ registration +^/_matrix/client/v1/register/m.login.registration_token/validity$ registration +^/_matrix/client/(r0|v3|unstable)/password_policy$ registration + +# Event sending requests +^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/redact event_senders +^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/send event_senders +^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/state/ event_senders +^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/(join|invite|leave|ban|unban|kick)$ event_senders +^/_matrix/client/(api/v1|r0|v3|unstable)/join/ event_senders +^/_matrix/client/(api/v1|r0|v3|unstable)/knock/ event_senders +^/_matrix/client/(api/v1|r0|v3|unstable)/profile/ event_senders + +# User directory search requests +^/_matrix/client/(r0|v3|unstable)/user_directory/search$ user_dir + +# Additional REST GET requests +^/_matrix/client/(api/v1|r0|v3|unstable)/pushrules/ additional_rest + +# Pagination requests +# Must be handled by the same worker the user uses. Either loadbalance to source or only one worker +^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/messages$ pagination + +# for all SSO providers +^/_matrix/client/(api/v1|r0|v3|unstable)/login/sso/redirect sso +^/_synapse/client/pick_idp$ sso +^/_synapse/client/pick_username sso +^/_synapse/client/new_user_consent$ sso +^/_synapse/client/sso_register$ sso + +# OpenID Connect requests. +^/_synapse/client/oidc/callback$ oidc + +# SAML requests. +^/_synapse/client/saml2/authn_response$ saml + +# CAS requests. +^/_matrix/client/(api/v1|r0|v3|unstable)/login/cas/ticket$ cas + +# Typing stream +^/_matrix/client/(api/v1|r0|v3|unstable)/rooms/.*/typing typing + +# To-device stream +^/_matrix/client/(r0|v3|unstable)/sendToDevice/ to_device + +# Account-data stream +^/_matrix/client/(r0|v3|unstable)/.*/tags account_data +^/_matrix/client/(r0|v3|unstable)/.*/account_data account_data + +# Receipts stream +^/_matrix/client/(r0|v3|unstable)/rooms/.*/receipt receipts +^/_matrix/client/(r0|v3|unstable)/rooms/.*/read_markers receipts + +# Presence stream +^/_matrix/client/(api/v1|r0|v3|unstable)/presence/ presence + +# Media endpoints +^/_matrix/media/ media +^/_synapse/admin/v1/purge_media_cache$ media +^/_synapse/admin/v1/room/.*/media.*$ media +^/_synapse/admin/v1/user/.*/media.*$ media +^/_synapse/admin/v1/media/.*$ media +^/_synapse/admin/v1/quarantine_media/.*$ media +^/_synapse/admin/v1/users/.*/media$ media + diff --git a/.compose/haproxy/lua_function_to_worker.map_rewrite.cfg b/.compose/haproxy/lua_function_to_worker.map_rewrite.cfg new file mode 100644 index 00000000..27dddec2 --- /dev/null +++ b/.compose/haproxy/lua_function_to_worker.map_rewrite.cfg @@ -0,0 +1,35 @@ +# NO LUA PATTERNS OR REGEX READ HERE. + +# Jobs that can be loadbalanced between numerous workers :: genworker +# main worker/synapse instance :: matrix +# indivisible worker : jobs that must not be divided into multiple workers :: indworker +# media : should be handled by media worker + +# client & federation +synchrotron matrix +federation_reader matrix +federation_inbound matrix +client matrix +encryption matrix +registration matrix +event_senders matrix +user_dir matrix +additional_rest matrix + +pagination matrix + +# sso +sso matrix +oidc matrix +saml matrix +cas matrix + +# streams +typing matrix +to_device matrix +account_data matrix +receipts matrix +presence matrix + +# media +media matrix diff --git a/.compose/haproxy/synapse_worker_endpoint_indexer.lua b/.compose/haproxy/synapse_worker_endpoint_indexer.lua new file mode 100644 index 00000000..1f8c2855 --- /dev/null +++ b/.compose/haproxy/synapse_worker_endpoint_indexer.lua @@ -0,0 +1,166 @@ +-- AIM OF FILE : Allow redirecting endpoints to specific workers for synapse +-- FILES IT REQUIRES : lua_endpoint_to_function.map.cfg and lua_function_to_worker.map.cfg +-- NOTE : THE PATH IS HARDCODED HERE + +local default_worker = "matrix" -- THE DEFAULT WORKER IF THE ENDPOINT IS NOT RECOGNIZED +-- matrix is the name of the backend in haproxy.cfg + +local endp_to_func_file, err1 = io.open("/usr/local/etc/haproxy/lua_endpoint_to_function.map_rewrite.cfg", "r") +local func_to_worker_file, err2 = io.open("/usr/local/etc/haproxy/lua_function_to_worker.map_rewrite.cfg", "r") + +local endpoint_regex_table, worker_table = {}, {} +local functions_found = {} + +-- to live-debug where each received endpoint gets redirected to in terms of backend +local debug = false -- set to true to print endpoint associations. +local print_debug = "[HAProxy|LUA] " + +local function print_debug_fn(...) + if debug then + print(...) + end +end + +assert(endp_to_func_file, "ENDPOINT TO FUNC MAP FILE NOT FOUND") +assert(func_to_worker_file, "FUNC TO WORKER MAP FILE NOT FOUND") + +function parse_or_tbl(str_tbl) + --[[ + Duplicates the entries in str_tbl when they are in the an (.. | ..) format + Returns the number of instances of the pattern found + ex : {"(hi|there)"} becomes {"hi", "there"}, with 1 returned + ]] + local count = 0 + local to_add = {} -- list of elements to add + local to_remove = {} -- contains list of keys to remove + + for k,v in pairs(str_tbl) do + if ( v == nil ) then + goto continue_parse + end + + line = v + -- v is the string to multiply given the "or" + local split_first, split_last = line:find("%((.-%|.-)%)") + if (split_first ~= nil) and (split_last ~= nil) then + split_first = split_first + 1 + split_last = split_last - 1 + + local to_split = line:sub(split_first, split_last).."|" + + local splits = {} + to_split:gsub("([^".."%|".."]*)".."%|", function(capture) + table.insert(splits, capture) + end) + + count = count + 1 + + to_remove[#to_remove+1] = k + + for k2, v2 in pairs(splits) do + to_add[#to_add+1] = line:sub(1, split_first-2)..v2..line:sub(split_last+2, string.len(line)) + end + end + ::continue_parse:: + end + + for k,v in pairs(to_remove) do + if (str_tbl[k] ~= nil) then + table.remove(str_tbl, k) + end + end + + for k,v in pairs(to_add) do + table.insert(str_tbl, v) + end + + return count +end + +-- Associated each endpoint to a function +for line in endp_to_func_file:lines() do + if line:sub(1,1) == "#" then + goto continue + end + + local first, second = line:match("(%S+) (%S+)") + + if (first == nil) or (second==nil) then + goto continue + end + local endpoints = {first} + + while (parse_or_tbl(endpoints) > 0) do + -- duplicates the entries in endpoints + end + + for k,v in pairs(endpoints) do + endpoint_regex_table[v] = second + functions_found[v] = true + print_debug_fn(print_debug, "associated endpoint", v, second) + end + + ::continue:: +end + +print_debug_fn(print_debug, "--------------------------------") + +-- Associate each function to a worker +for line in func_to_worker_file:lines() do + if line:sub(1,1) == "#" then + goto continue_2 + end + + local first, second = line:match("(%S+) (%S+)") + + if (first == nil) or (second==nil) then + goto continue_2 + end + + worker_table[first] = second + print_debug_fn(print_debug, "associated function", first, second) + ::continue_2:: +end + +function log(message) + -- Logs the message in haproxy console if it debug is enabled above + if debug then + core.log(core.info, message) + end +end + +core.register_fetches("path_to_worker", function(txn) + --[[ + TODO: Documentation + ]]-- + local path = txn.f:path() + log(print_debug.." PATH OF REQUEST "..path) + local func, worker; + + if (path == nil) then + log(print_debug.." PATH NOT FOUND") + worker=default_worker + goto finish_calc + end + + for k,v in pairs(endpoint_regex_table) do + --core.log(core.info, print_debug.." TRYING "..k) + if (path:match(k)) then + func = v + break; + end + end + + if (func == nil) then + log(print_debug.." FUNCTION NOT FOUND") + worker=default_worker + goto finish_calc + end + + worker = worker_table[func] or default_worker + + ::finish_calc:: + log(print_debug.." USING WORKER "..worker) + + return worker +end) \ No newline at end of file diff --git a/.compose/lemon/create-user.sh b/.compose/lemon/create-user.sh new file mode 100755 index 00000000..cfcaabb4 --- /dev/null +++ b/.compose/lemon/create-user.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +# File : create-user.sh +# License : AGPL-3.0-or-later +# Author : Pierre 'McFly' Marty +# Date : 14.01.2025 +# Last Modified Date: 27.01.2025 +# Last Modified By : Pierre 'McFly' Marty + +readonly nickname="${1:-dwho}" +readonly givenname="${2:-Doctor Who}" +readonly password="${3:-dwho}" + +echo -e "Adding user: ${givenname} (${nickname})\n\tpass: ${password}" +sqlite3 lemon.db "insert into users values ('${nickname}','${givenname}','${nickname}@docker.localhost','${password}')" +[[ "$?" == '0' ]] && echo "Done." diff --git a/.compose/lemon/init-db.sh b/.compose/lemon/init-db.sh new file mode 100755 index 00000000..faf8ce07 --- /dev/null +++ b/.compose/lemon/init-db.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# File : init-db.sh +# License : AGPL-3.0-or-later +# Author : Pierre 'McFly' Marty +# Date : 14.01.2025 +# Last Modified Date: 27.01.2025 +# Last Modified By : Pierre 'McFly' Marty + +echo "Inflating Auth DB." +sqlite3 lemon.db "Create table if not exists users (uid text,name text,mail text,password text);" +[[ "$?" == '0' ]] && echo "Done." + +# # nickname # Full Name # password +./create-user.sh 'dwho' 'Doctor Who' 'dwho' +./create-user.sh 'rtyler' 'R. Tyler' 'rtyler' +./create-user.sh 'jbinks' 'Jar Jar Binks' 'jbinks' diff --git a/.compose/lemon/lmConf-1.json b/.compose/lemon/lmConf-1.json new file mode 100755 index 00000000..5a289d33 --- /dev/null +++ b/.compose/lemon/lmConf-1.json @@ -0,0 +1,529 @@ +{ + "ADPwdExpireWarning" : 0, + "ADPwdMaxAge" : 0, + "SMTPServer" : "", + "SMTPTLS" : "", + "SSLAuthnLevel" : 5, + "SSLIssuerVar" : "SSL_CLIENT_I_DN", + "SSLVar" : "SSL_CLIENT_S_DN_Email", + "SSLVarIf" : {}, + "activeTimer" : 1, + "apacheAuthnLevel" : 3, + "applicationList" : { + "1matrix" : { + "catname" : "Matrix clients", + "Twake" : { + "options" : { + "description" : "Twake web client", + "display" : "on", + "logo" : "demo.png", + "name" : "Twake", + "uri" : "https://chat.docker.localhost/" + }, + "type" : "application" + }, + "type" : "category" + } + }, + "authChoiceParam" : "lmAuth", + "authentication" : "DBI", + "available2F" : "UTOTP,TOTP,U2F,REST,Mail2F,Ext2F,WebAuthn,Yubikey,Radius,Password", + "available2FSelfRegistration" : "Password,TOTP,U2F,WebAuthn,Yubikey", + "bruteForceProtectionLockTimes" : "15, 30, 60, 300, 600", + "bruteForceProtectionMaxAge" : 300, + "bruteForceProtectionMaxFailed" : 3, + "bruteForceProtectionMaxLockTime" : 900, + "bruteForceProtectionTempo" : 30, + "captcha_login_enabled" : 0, + "captcha_mail_enabled" : 1, + "captcha_register_enabled" : 1, + "captcha_size" : 6, + "casAccessControlPolicy" : "none", + "casAuthnLevel" : 1, + "casTicketExpiration" : 0, + "certificateResetByMailCeaAttribute" : "description", + "certificateResetByMailCertificateAttribute" : "userCertificate;binary", + "certificateResetByMailURL" : "https://auth.docker.localhost/certificateReset", + "certificateResetByMailValidityDelay" : 0, + "cfgAuthor" : "The LemonLDAP::NG team", + "cfgDate" : "1627287638", + "cfgNum" : "1", + "cfgVersion" : "2.0.16", + "checkDevOpsCheckSessionAttributes" : 1, + "checkDevOpsDisplayNormalizedHeaders" : 1, + "checkDevOpsDownload" : 1, + "checkHIBPRequired" : 1, + "checkHIBPURL" : "https://api.pwnedpasswords.com/range/", + "checkMsg" : 5, + "checkTime" : 600, + "checkUserDisplayComputedSession" : 1, + "checkUserDisplayEmptyHeaders" : 0, + "checkUserDisplayEmptyValues" : 0, + "checkUserDisplayHiddenAttributes" : 0, + "checkUserDisplayHistory" : 0, + "checkUserDisplayNormalizedHeaders" : 0, + "checkUserDisplayPersistentInfo" : 0, + "checkUserHiddenAttributes" : "_loginHistory, _session_id, hGroups", + "checkUserIdRule" : 1, + "checkXSS" : 1, + "confirmFormMethod" : "post", + "contextSwitchingIdRule" : 1, + "contextSwitchingPrefix" : "switching", + "contextSwitchingRule" : 0, + "contextSwitchingStopWithLogout" : 1, + "cookieName" : "lemonldap", + "corsAllow_Credentials" : "true", + "corsAllow_Headers" : "*", + "corsAllow_Methods" : "POST,GET", + "corsAllow_Origin" : "*", + "corsEnabled" : 1, + "corsExpose_Headers" : "*", + "corsMax_Age" : "86400", + "crowdsecAction" : "reject", + "cspConnect" : "'self'", + "cspDefault" : "'self'", + "cspFont" : "'self'", + "cspFormAction" : "*", + "cspFrameAncestors" : "", + "cspImg" : "'self' data:", + "cspScript" : "'self'", + "cspStyle" : "'self'", + "dbiAuthChain" : "dbi:SQLite:dbname=/db/lemon.db", + "dbiAuthLoginCol" : "uid", + "dbiAuthPassword" : "", + "dbiAuthPasswordCol" : "password", + "dbiAuthTable" : "users", + "dbiAuthUser" : "", + "dbiAuthnLevel" : 2, + "dbiExportedVars" : { + "uid": "uid", + "name": "name", + "mail": "mail" + }, + "decryptValueRule" : 0, + "defaultNewKeySize" : 2048, + "demoExportedVars" : { + "cn" : "cn", + "mail" : "mail", + "uid" : "uid" + }, + "displaySessionId" : 1, + "domain" : "docker.localhost", + "eventQueueName" : "llng_events", + "exportedHeaders" : {}, + "exportedVars" : {}, + "ext2fActivation" : 0, + "ext2fCodeActivation" : "\\d{6}", + "facebookAuthnLevel" : 1, + "facebookExportedVars" : {}, + "facebookUserField" : "id", + "failedLoginNumber" : 5, + "findUserControl" : "^[*\\w]+$", + "findUserWildcard" : "*", + "formTimeout" : 120, + "githubAuthnLevel" : 1, + "githubScope" : "user:email", + "githubUserField" : "login", + "globalLogoutRule" : 0, + "globalLogoutTimer" : 1, + "globalStorage" : "Apache::Session::File", + "globalStorageOptions" : { + "Directory" : "/var/lib/lemonldap-ng/sessions", + "LockDirectory" : "/var/lib/lemonldap-ng/sessions/lock", + "generateModule" : "Lemonldap::NG::Common::Apache::Session::Generate::SHA256" + }, + "gpgAuthnLevel" : 5, + "gpgDb" : "", + "grantSessionRules" : {}, + "groups" : {}, + "handlerInternalCache" : 15, + "handlerServiceTokenTTL" : 30, + "hiddenAttributes" : "_password, _2fDevices", + "hideOldPassword" : 1, + "httpOnly" : 1, + "https" : -1, + "ignorePollersDelay" : 300, + "ignorePollersLimit" : 10, + "impersonationHiddenAttributes" : "_2fDevices, _loginHistory", + "impersonationIdRule" : 1, + "impersonationMergeSSOgroups" : 0, + "impersonationPrefix" : "real_", + "impersonationRule" : 0, + "impersonationSkipEmptyValues" : 1, + "infoFormMethod" : "get", + "issuerDBCASPath" : "^/cas/", + "issuerDBCASRule" : 1, + "issuerDBGetParameters" : {}, + "issuerDBGetPath" : "^/get/", + "issuerDBGetRule" : 1, + "issuerDBJitsiMeetTokensPath" : "^/jitsi/", + "issuerDBJitsiMeetTokensRule" : 1, + "issuerDBOpenIDConnectActivation" : 1, + "issuerDBOpenIDConnectPath" : "^/oauth2/", + "issuerDBOpenIDConnectRule" : 1, + "issuerDBOpenIDPath" : "^/openidserver/", + "issuerDBOpenIDRule" : 1, + "issuerDBSAMLPath" : "^/saml/", + "issuerDBSAMLRule" : 1, + "issuersTimeout" : 120, + "jitsiExpiration" : "300", + "jitsiSigningAlg" : "RS256", + "jsRedirect" : 0, + "key" : "^vmTGvh{+]5!ToB?", + "krbAuthnLevel" : 3, + "krbRemoveDomain" : 1, + "ldapAuthnLevel" : 2, + "ldapBase" : "dc=example,dc=com", + "ldapExportedVars" : { + "cn" : "cn", + "mail" : "mail", + "uid" : "uid" + }, + "ldapGroupAttributeName" : "member", + "ldapGroupAttributeNameGroup" : "dn", + "ldapGroupAttributeNameSearch" : "cn", + "ldapGroupAttributeNameUser" : "dn", + "ldapGroupObjectClass" : "groupOfNames", + "ldapIOTimeout" : 10, + "ldapPasswordResetAttribute" : "pwdReset", + "ldapPasswordResetAttributeValue" : "TRUE", + "ldapPwdEnc" : "utf-8", + "ldapSearchDeref" : "find", + "ldapServer" : "ldap://localhost", + "ldapTimeout" : 10, + "ldapUsePasswordResetAttribute" : 1, + "ldapVerify" : "require", + "ldapVersion" : 3, + "linkedInAuthnLevel" : 1, + "linkedInFields" : "id,first-name,last-name,email-address", + "linkedInScope" : "r_liteprofile r_emailaddress", + "linkedInUserField" : "emailAddress", + "localSessionStorage" : "Cache::FileCache", + "localSessionStorageOptions" : { + "cache_depth" : 3, + "cache_root" : "/var/lib/lemonldap-ng/cache", + "default_expires_in" : 600, + "directory_umask" : "007", + "namespace" : "lemonldap-ng-sessions" + }, + "locationDetectGeoIpLanguages" : "en, fr", + "locationRules" : { + "auth.docker.localhost" : { + "(?#checkUser)^/checkuser" : "inGroup(\"timelords\")", + "(?#errors)^/lmerror/" : "accept", + "default" : "accept" + }, + "chat.docker.localhost" : { + "default" : "accept" + }, + "manager.docker.localhost" : { + "(?#Configuration)^/(.*?\\.(fcgi|psgi)/)?(manager\\.html|confs|prx/|$)" : "accept", + "(?#Notifications)/(.*?\\.(fcgi|psgi)/)?notifications" : "inGroup(\"timelords\") or $uid eq \"rtyler\"", + "(?#Sessions)/(.*?\\.(fcgi|psgi)/)?sessions" : "inGroup(\"timelords\") or $uid eq \"rtyler\"", + "default" : "inGroup(\"timelords\") or $uid eq \"rtyler\"" + } + }, + "loginHistoryEnabled" : 1, + "logoutServices" : {}, + "lwpOpts" : { + "timeout" : 10 + }, + "lwpSslOpts" : { + "SSL_verify_mode" : 0, + "verify_hostname" : false + }, + "macros" : { + "UA" : "$ENV{HTTP_USER_AGENT}", + "_whatToTrace" : "$_auth eq 'SAML' ? lc($_user.'@'.$_idpConfKey) : $_auth eq 'OpenIDConnect' ? lc($_user.'@'.$_oidc_OP) : lc($_user)" + }, + "mail2fActivation" : 0, + "mail2fCodeRegex" : "\\d{6}", + "mailCharset" : "utf-8", + "mailFrom" : "noreply@docker.localhost", + "mailSessionKey" : "mail", + "mailTimeout" : 0, + "mailUrl" : "https://auth.docker.localhost/resetpwd", + "managerDn" : "", + "managerPassword" : "", + "max2FDevices" : 10, + "max2FDevicesNameLength" : 20, + "messageBrokerOptions" : {}, + "multiValuesSeparator" : "; ", + "mySessionAuthorizedRWKeys" : [ + "_appsListOrder", + "_oidcConnectedRP", + "_oidcConsents" + ], + "newLocationWarningLocationAttribute" : "ipAddr", + "newLocationWarningLocationDisplayAttribute" : "", + "newLocationWarningMaxValues" : "0", + "notification" : 0, + "notificationDefaultCond" : "", + "notificationServerPOST" : 1, + "notificationServerSentAttributes" : "uid reference date title subtitle text check", + "notificationStorage" : "File", + "notificationStorageOptions" : { + "dirName" : "/var/lib/lemonldap-ng/notifications" + }, + "notificationWildcard" : "allusers", + "notificationsMaxRetrieve" : 3, + "notifyDeleted" : 1, + "nullAuthnLevel" : 0, + "oidcAuthnLevel" : 1, + "oidcOPMetaDataExportedVars" : {}, + "oidcOPMetaDataJSON" : {}, + "oidcOPMetaDataJWKS" : {}, + "oidcOPMetaDataOptions" : {}, + "oidcRPCallbackGetParam" : "openidconnectcallback", + "oidcRPMetaDataExportedVars" : { + "matrix" : { + "email" : "mail", + "family_name" : "name", + "given_name" : "name", + "name" : "name", + "nickname" : "uid", + "preferred_username" : "uid" + } + }, + "oidcRPMetaDataMacros" : null, + "oidcRPMetaDataOptions" : { + "matrix" : { + "oidcRPMetaDataOptionsAccessTokenClaims" : 0, + "oidcRPMetaDataOptionsAccessTokenJWT" : 0, + "oidcRPMetaDataOptionsAccessTokenSignAlg" : "RS256", + "oidcRPMetaDataOptionsAllowClientCredentialsGrant" : 0, + "oidcRPMetaDataOptionsAllowOffline" : 0, + "oidcRPMetaDataOptionsAllowPasswordGrant" : 0, + "oidcRPMetaDataOptionsBypassConsent" : 1, + "oidcRPMetaDataOptionsClientID" : "matrix1", + "oidcRPMetaDataOptionsClientSecret" : "matrix1", + "oidcRPMetaDataOptionsIDTokenForceClaims" : 0, + "oidcRPMetaDataOptionsIDTokenSignAlg" : "RS256", + "oidcRPMetaDataOptionsLogoutBypassConfirm" : 0, + "oidcRPMetaDataOptionsLogoutSessionRequired" : 1, + "oidcRPMetaDataOptionsLogoutType" : "back", + "oidcRPMetaDataOptionsLogoutUrl" : "https://matrix.docker.localhost/_synapse/client/oidc/backchannel_logout", + "oidcRPMetaDataOptionsPublic" : 0, + "oidcRPMetaDataOptionsRedirectUris" : "https://matrix.docker.localhost/_synapse/client/oidc/callback", + "oidcRPMetaDataOptionsRefreshToken" : 0, + "oidcRPMetaDataOptionsRequirePKCE" : 0, + "oidcRPMetaDataOptionsTokenXAuthorizedMatrix" : "docker.localhost" + } + }, + "oidcRPMetaDataOptionsExtraClaims" : null, + "oidcRPMetaDataScopeRules" : null, + "oidcRPStateTimeout" : 600, + "oidcServiceAccessTokenExpiration" : 3600, + "oidcServiceAllowAuthorizationCodeFlow" : 1, + "oidcServiceAllowImplicitFlow" : 0, + "oidcServiceAuthorizationCodeExpiration" : 60, + "oidcServiceDynamicRegistrationExportedVars" : {}, + "oidcServiceDynamicRegistrationExtraClaims" : {}, + "oidcServiceEncAlgorithmAlg" : "RSA-OAEP", + "oidcServiceEncAlgorithmEnc" : "A256GCM", + "oidcServiceIDTokenExpiration" : 3600, + "oidcServiceIgnoreScopeForClaims" : 1, + "oidcServiceKeyIdSig" : "oMGHInscAW3Nsa0FcnCnDA", + "oidcServiceKeyTypeEnc" : "RSA", + "oidcServiceKeyTypeSig" : "RSA", + "oidcServiceMetaDataAuthnContext" : { + "loa-1" : 1, + "loa-2" : 2, + "loa-3" : 3, + "loa-4" : 4, + "loa-5" : 5 + }, + "oidcServiceMetaDataAuthorizeURI" : "authorize", + "oidcServiceMetaDataBackChannelURI" : "blogout", + "oidcServiceMetaDataCheckSessionURI" : "checksession.html", + "oidcServiceMetaDataEndSessionURI" : "logout", + "oidcServiceMetaDataFrontChannelURI" : "flogout", + "oidcServiceMetaDataIntrospectionURI" : "introspect", + "oidcServiceMetaDataJWKSURI" : "jwks", + "oidcServiceMetaDataRegistrationURI" : "register", + "oidcServiceMetaDataTokenURI" : "token", + "oidcServiceMetaDataUserInfoURI" : "userinfo", + "oidcServiceNewKeyTypeSig" : "RSA", + "oidcServiceOfflineSessionExpiration" : 2592000, + "oidcServiceOldKeyTypeEnc" : "RSA", + "oidcServiceOldKeyTypeSig" : "RSA", + "oidcServicePrivateKeySig" : "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDywteBzIOlhKc4\nO+vhMStDYOpPYrWDOodkUZ7OsxlWVNZ/b/lqIFS56+MHPkKNQuT4zZCyO8bEKmmR\nZ6kPFJoGbO1zJCPQ/RKjimX4J/5gDb1BAlo+6agJi55e3Bw0zKNJDU0mRyedcIzW\n7ywTgyj6B35pl/Sfloi4Q1XEizHar+26h66SOEtnppMxGvwsxO8gFWz26CPmalvY\n5GNYR0txbXUZn7I4kDa4mMWgNfeocWc78Qbt4RV5EuQdbRh1sou4tL9Nn4EuGhg0\nmfsSI0xVAj7f82Wn3kW6qEbhuejrY7aqmZjN7yrMKtCBuV7o4hVrjYLuM2j0mInY\nMy5nRNOVAgMBAAECggEAJ145nK8R2lG83H27LvXOUkrxNJaJYRKoyjgCTPr2bO2t\nK1V5WSCNHOmIE7ChEk962m5bvMu83CsUm6P34p4wrEIV78o4lLe1whe7mZbCxcj0\nnApJoFI8EfA2aqO/X0CgakRh8ocvgXSzIlf/CdsHViTI907ROOAso9Unn4wDNbdp\nMrhi3H2SnA+ewzj85WygBVTNQmVBjJSSLXTQRkfHye0ztvQm59gqqaJaM2rkBjvA\nlPWAVsgakOk4pgClKElCsIjWPJwdYtcd8VJrwnro5J9KhMwB//AArGgqOaXUHnLH\nv5aZZp6FjV/M3BxbSp4cG6hXmK1hrDFLecRddYP1gQKBgQD+Y4/ee57Z0E2V8833\nYfrK3F23sfxmZ7zUwEbgFXUfRy3RVW7Hbc7PAJzxzrk+LYk/zaZrrfEJguqG2O6m\nVNYkqxKu69Nn964CMdV15JGxVzpzsN5adKlcvKVVv9gx2rF3SMUOHiRutj2BlUtO\niCq0G3jFsXWIRzePig9PbWP6CQKBgQD0TG2DeDDUgKbeJYIzXfmCvGxlm5MZqCc/\nK7d8P9U0svG//jJRTsa9hcLjk7N24CzhLNHyJmT7dh1Xy1oLyHNPZ4nQRmCe+HUf\nu0SK10WZ2K55ekUmqS+xSuDFWJtWa5SE46cKg0fKu7YkiDKI1s6I3qrF4lew2aDE\n2p8GJRrgLQKBgCh2PZPtpb6PW0fWl5QZiYJqup1VOggvx+EvFBbgUti+wZLiO9SM\nqrBSMKRldSFmrMXxN984s3YH1LXOG2dpZwY+D6Ky79VBl/PRaVpvGJ1Uen+cSkGo\n/Kc7ejDBaunDFycZ8/3i3Xiek/ngfTHohqJPHE6Vg1RBv5ydIQJJK/XBAoGAU1XO\n9c4GOjc4tQbuhz9DYgmMoIyVfWcTHEV5bfUIcdWpCelYmMval8QNWzyDN8X5CUcU\nxxm50N3V3KENsn9KdofHRzj6tL/klFJ5azNMFtMHkYDYHfwQvNXiHu++7Zf9LefK\nj5eA4fNuir+7HVrJUX9DmgVADJ/wa7Z4EMyPgnECgYA/NLUs4920h10ie5lFffpM\nqq6CRcBjsQ7eGK9UI1Z2KZUh94eqIENSJ7whBjXKvJJvhAlH4//lVFMMRs7oJePY\nThg+8In7PB64yMOIJZLc5Fekn9aGG6YtErPzePQkXSYCKZxWl5EpjQZGgPRVkNtD\n2nflyJLjiCbTjeNgWIOZlw==\n-----END PRIVATE KEY-----\n", + "oidcServicePublicKeySig" : "-----BEGIN CERTIFICATE-----\nMIICuDCCAaCgAwIBAgIEFU77HjANBgkqhkiG9w0BAQsFADAeMRwwGgYDVQQDDBNt\nYXRyaXgubGluYWdvcmEuY29tMB4XDTIzMDIxNTAzMTk0NloXDTQzMDIxMDAzMTk0\nNlowHjEcMBoGA1UEAwwTbWF0cml4LmxpbmFnb3JhLmNvbTCCASIwDQYJKoZIhvcN\nAQEBBQADggEPADCCAQoCggEBAPLC14HMg6WEpzg76+ExK0Ng6k9itYM6h2RRns6z\nGVZU1n9v+WogVLnr4wc+Qo1C5PjNkLI7xsQqaZFnqQ8UmgZs7XMkI9D9EqOKZfgn\n/mANvUECWj7pqAmLnl7cHDTMo0kNTSZHJ51wjNbvLBODKPoHfmmX9J+WiLhDVcSL\nMdqv7bqHrpI4S2emkzEa/CzE7yAVbPboI+ZqW9jkY1hHS3FtdRmfsjiQNriYxaA1\n96hxZzvxBu3hFXkS5B1tGHWyi7i0v02fgS4aGDSZ+xIjTFUCPt/zZafeRbqoRuG5\n6OtjtqqZmM3vKswq0IG5XujiFWuNgu4zaPSYidgzLmdE05UCAwEAATANBgkqhkiG\n9w0BAQsFAAOCAQEArNmGxZVvmvdOLctv+zQ+npzQtOTaJcf+r/1xYuM4FZVe4yLc\ny9ElDskoDWjvQU7jKeJeaDOYgMJQNrek8Doj8uHPWNe6jYFa62Csg9aPz6e8qbtq\nWI+sXds5GJd6xZ8mi2L4MdT/tf8dBgcgybuoRyhBtJwG1rLNAYkeXMxkBzOFcU7K\nR/SZ0q9ToLAWFDhn42MTjPN3t6GwKDzGNsM/SI/3WvUwpQbtK91hjPnNDwKiAtGG\nfUteuigfXY+0hEcQwJdR0St/FQ8UYYcAB5YT9IkT1wCcU5LfPHCBf3OXNpbnQsHh\netQMKLibM6wWdXNwmsd1szO66ft3QZ4h4EG3Vw==\n-----END CERTIFICATE-----\n", + "oidcStorageOptions" : {}, + "okta2fActivation" : 0, + "openIdAuthnLevel" : 1, + "openIdExportedVars" : {}, + "openIdIDPList" : "0;", + "openIdSPList" : "0;", + "openIdSreg_email" : "mail", + "openIdSreg_fullname" : "cn", + "openIdSreg_nickname" : "uid", + "openIdSreg_timezone" : "_timezone", + "pamAuthnLevel" : 2, + "pamService" : "login", + "password2fActivation" : 0, + "password2fSelfRegistration" : 0, + "password2fUserCanRemoveKey" : 1, + "passwordDB" : "Demo", + "passwordPolicyActivation" : 1, + "passwordPolicyMaxSize" : 0, + "passwordPolicyMinDigit" : 0, + "passwordPolicyMinLower" : 0, + "passwordPolicyMinSize" : 0, + "passwordPolicyMinSpeChar" : 0, + "passwordPolicyMinUpper" : 0, + "passwordPolicySpecialChar" : "__ALL__", + "passwordResetAllowedRetries" : 3, + "persistentSessionAttributes" : "_loginHistory _2fDevices notification_", + "persistentStorage" : "Apache::Session::File", + "persistentStorageOptions" : { + "Directory" : "/var/lib/lemonldap-ng/psessions", + "LockDirectory" : "/var/lib/lemonldap-ng/psessions/lock" + }, + "port" : -1, + "portal" : "https://auth.docker.localhost/", + "portalAntiFrame" : 1, + "portalCheckLogins" : 1, + "portalDisplayAppslist" : 1, + "portalDisplayChangePassword" : "$_auth =~ /^(LDAP|DBI|Demo)$/", + "portalDisplayGeneratePassword" : 1, + "portalDisplayLoginHistory" : 1, + "portalDisplayLogout" : 1, + "portalDisplayOidcConsents" : "$_oidcConsents && $_oidcConsents =~ /\\w+/", + "portalDisplayOrder" : "Appslist ChangePassword LoginHistory OidcConsents Logout", + "portalDisplayRefreshMyRights" : 1, + "portalDisplayRegister" : 1, + "portalErrorOnExpiredSession" : 1, + "portalFavicon" : "common/favicon.ico", + "portalForceAuthnInterval" : 5, + "portalMainLogo" : "common/logos/logo_llng_400px.png", + "portalPingInterval" : 60000, + "portalRequireOldPassword" : 1, + "portalSkin" : "bootstrap", + "portalSkinBackground" : "1280px-Cedar_Breaks_National_Monument_partially.jpg", + "portalUserAttr" : "_user", + "proxyAuthServiceChoiceParam" : "lmAuth", + "proxyAuthnLevel" : 2, + "radius2fActivation" : 0, + "radius2fRequestAttributes" : {}, + "radius2fTimeout" : 20, + "radiusAuthnLevel" : 3, + "radiusExportedVars" : {}, + "radiusRequestAttributes" : {}, + "randomPasswordRegexp" : "[A-Z]{3}[a-z]{5}.\\d{2}", + "redirectFormMethod" : "get", + "registerDB" : "Null", + "registerTimeout" : 0, + "registerUrl" : "https://auth.docker.localhost/register", + "reloadTimeout" : 5, + "reloadUrls" : { + "localhost" : "https://reload.docker.localhost/reload" + }, + "rememberAuthChoiceRule" : 0, + "rememberCookieName" : "llngrememberauthchoice", + "rememberCookieTimeout" : 31536000, + "rememberTimer" : 5, + "remoteGlobalStorage" : "Lemonldap::NG::Common::Apache::Session::SOAP", + "remoteGlobalStorageOptions" : { + "ns" : "https://auth.docker.localhost/Lemonldap/NG/Common/PSGI/SOAPService", + "proxy" : "https://auth.docker.localhost/sessions" + }, + "requireToken" : 1, + "rest2fActivation" : 0, + "restAuthnLevel" : 2, + "restClockTolerance" : 15, + "sameSite" : "", + "samlAttributeAuthorityDescriptorAttributeServiceSOAP" : "urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/AA/SOAP;", + "samlAuthnContextMapKerberos" : 4, + "samlAuthnContextMapPassword" : 2, + "samlAuthnContextMapPasswordProtectedTransport" : 3, + "samlAuthnContextMapTLSClient" : 5, + "samlEntityID" : "#PORTAL#/saml/metadata", + "samlIDPSSODescriptorArtifactResolutionServiceArtifact" : "1;0;urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/artifact", + "samlIDPSSODescriptorSingleLogoutServiceHTTPPost" : "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST;#PORTAL#/saml/singleLogout;#PORTAL#/saml/singleLogoutReturn", + "samlIDPSSODescriptorSingleLogoutServiceHTTPRedirect" : "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect;#PORTAL#/saml/singleLogout;#PORTAL#/saml/singleLogoutReturn", + "samlIDPSSODescriptorSingleLogoutServiceSOAP" : "urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/singleLogoutSOAP;", + "samlIDPSSODescriptorSingleSignOnServiceHTTPArtifact" : "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact;#PORTAL#/saml/singleSignOnArtifact;", + "samlIDPSSODescriptorSingleSignOnServiceHTTPPost" : "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST;#PORTAL#/saml/singleSignOn;", + "samlIDPSSODescriptorSingleSignOnServiceHTTPRedirect" : "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect;#PORTAL#/saml/singleSignOn;", + "samlIDPSSODescriptorWantAuthnRequestsSigned" : 1, + "samlMetadataForceUTF8" : 1, + "samlNameIDFormatMapEmail" : "mail", + "samlNameIDFormatMapKerberos" : "uid", + "samlNameIDFormatMapWindows" : "uid", + "samlNameIDFormatMapX509" : "mail", + "samlOrganizationDisplayName" : "Example", + "samlOrganizationName" : "Example", + "samlOrganizationURL" : "https://www.docker.localhost", + "samlOverrideIDPEntityID" : "", + "samlRelayStateTimeout" : 600, + "samlSPSSODescriptorArtifactResolutionServiceArtifact" : "1;0;urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/artifact", + "samlSPSSODescriptorAssertionConsumerServiceHTTPArtifact" : "0;1;urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact;#PORTAL#/saml/proxySingleSignOnArtifact", + "samlSPSSODescriptorAssertionConsumerServiceHTTPPost" : "1;0;urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST;#PORTAL#/saml/proxySingleSignOnPost", + "samlSPSSODescriptorAuthnRequestsSigned" : 1, + "samlSPSSODescriptorSingleLogoutServiceHTTPPost" : "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST;#PORTAL#/saml/proxySingleLogout;#PORTAL#/saml/proxySingleLogoutReturn", + "samlSPSSODescriptorSingleLogoutServiceHTTPRedirect" : "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect;#PORTAL#/saml/proxySingleLogout;#PORTAL#/saml/proxySingleLogoutReturn", + "samlSPSSODescriptorSingleLogoutServiceSOAP" : "urn:oasis:names:tc:SAML:2.0:bindings:SOAP;#PORTAL#/saml/proxySingleLogoutSOAP;", + "samlSPSSODescriptorWantAssertionsSigned" : 1, + "samlServiceSignatureMethod" : "RSA_SHA256", + "scrollTop" : 400, + "securedCookie" : 0, + "sessionDataToRemember" : {}, + "sfEngine" : "::2F::Engines::Default", + "sfManagerRule" : 1, + "sfRemovedMsgRule" : 0, + "sfRemovedNotifMsg" : "_removedSF_ expired second factor(s) has/have been removed (_nameSF_)!", + "sfRemovedNotifRef" : "RemoveSF", + "sfRemovedNotifTitle" : "Second factor notification", + "sfRequired" : 0, + "showLanguages" : 1, + "singleIP" : 0, + "singleSession" : 0, + "singleUserByIP" : 0, + "slaveAuthnLevel" : 2, + "slaveExportedVars" : {}, + "soapProxyUrn" : "urn:Lemonldap/NG/Common/PSGI/SOAPService", + "statusQueueName" : "llng_status", + "stayConnected" : 0, + "stayConnectedCookieName" : "llngconnection", + "stayConnectedTimeout" : 2592000, + "successLoginNumber" : 5, + "timeout" : 72000, + "timeoutActivity" : 0, + "timeoutActivityInterval" : 60, + "totp2fActivation" : 0, + "totp2fDigits" : 6, + "totp2fInterval" : 30, + "totp2fRange" : 1, + "totp2fSelfRegistration" : 0, + "totp2fUserCanRemoveKey" : 1, + "trustedBrowserRule" : 0, + "trustedBrowserUseTotp" : 1, + "twitterAuthnLevel" : 1, + "twitterUserField" : "screen_name", + "u2fActivation" : 0, + "u2fSelfRegistration" : 0, + "u2fUserCanRemoveKey" : 1, + "upgradeSession" : 1, + "useRedirectAjaxOnUnauthorized" : 1, + "useRedirectOnError" : 1, + "useSafeJail" : 1, + "userControl" : "^[\\w\\.\\-@]+$", + "userDB" : "Same", + "utotp2fActivation" : 0, + "viewerHiddenKeys" : "samlIDPMetaDataNodes, samlSPMetaDataNodes", + "webIDAuthnLevel" : 1, + "webIDExportedVars" : {}, + "webauthn2fActivation" : 0, + "webauthn2fAttestation" : "none", + "webauthn2fSelfRegistration" : 0, + "webauthn2fUserCanRemoveKey" : 1, + "webauthn2fUserVerification" : "preferred", + "webauthnAppId" : 1, + "webauthnAuthnLevel" : 3, + "whatToTrace" : "_whatToTrace", + "yubikey2fActivation" : 0, + "yubikey2fPublicIDSize" : 12, + "yubikey2fSelfRegistration" : 0, + "yubikey2fUserCanRemoveKey" : 1 +} diff --git a/.compose/lemon/openid-configuration.json b/.compose/lemon/openid-configuration.json new file mode 100644 index 00000000..75329437 --- /dev/null +++ b/.compose/lemon/openid-configuration.json @@ -0,0 +1,81 @@ +{ + "acr_values_supported" : [ + "loa-5", + "loa-3", + "loa-1", + "loa-4", + "loa-2" + ], + "authorization_endpoint" : "https://auth.docker.localhost/oauth2/authorize", + "backchannel_logout_session_supported" : true, + "backchannel_logout_supported" : true, + "claims_supported" : [ + "sub", + "iss", + "auth_time", + "acr", + "sid" + ], + "code_challenge_methods_supported" : [ + "plain", + "S256" + ], + "end_session_endpoint" : "https://auth.docker.localhost/oauth2/logout", + "frontchannel_logout_session_supported" : true, + "frontchannel_logout_supported" : true, + "grant_types_supported" : [ + "authorization_code" + ], + "id_token_signing_alg_values_supported" : [ + "none", + "HS256", + "HS384", + "HS512", + "RS256", + "RS384", + "RS512" + ], + "introspection_endpoint" : "https://auth.docker.localhost/oauth2/introspect", + "introspection_endpoint_auth_methods_supported" : [ + "client_secret_post", + "client_secret_basic" + ], + "issuer" : "https://auth.docker.localhost", + "jwks_uri" : "https://auth.docker.localhost/oauth2/jwks", + "request_parameter_supported" : true, + "request_uri_parameter_supported" : true, + "require_request_uri_registration" : false, + "response_modes_supported" : [ + "query", + "fragment", + "form_post" + ], + "response_types_supported" : [ + "code" + ], + "scopes_supported" : [ + "openid", + "profile", + "email", + "address", + "phone" + ], + "subject_types_supported" : [ + "public" + ], + "token_endpoint" : "https://auth.docker.localhost/oauth2/token", + "token_endpoint_auth_methods_supported" : [ + "client_secret_post", + "client_secret_basic" + ], + "userinfo_endpoint" : "https://auth.docker.localhost/oauth2/userinfo", + "userinfo_signing_alg_values_supported" : [ + "none", + "HS256", + "HS384", + "HS512", + "RS256", + "RS384", + "RS512" + ] +} diff --git a/.compose/lemon/root.conf b/.compose/lemon/root.conf new file mode 100644 index 00000000..f40894d3 --- /dev/null +++ b/.compose/lemon/root.conf @@ -0,0 +1,56 @@ +server { + listen 80; + server_name docker.localhost; + location /.well-known/matrix/client { + alias /var/www/matrix-client.json; + default_type application/json; + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Credentials' 'true'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + # + # Custom headers and headers various browsers *should* be OK with but aren't + # + add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; + # + # Tell client that this pre-flight info is valid for 20 days + # + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain charset=UTF-8'; + add_header 'Content-Length' 0; + return 204; + } + if ($request_method = 'GET') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Credentials' 'true'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; + } + } + location /.well-known/matrix/server { + alias /var/www/matrix-server.json; + default_type application/json; + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Credentials' 'true'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + # + # Custom headers and headers various browsers *should* be OK with but aren't + # + add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; + # + # Tell client that this pre-flight info is valid for 20 days + # + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain charset=UTF-8'; + add_header 'Content-Length' 0; + return 204; + } + if ($request_method = 'GET') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Allow-Credentials' 'true'; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; + add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type'; + } + } +} diff --git a/.compose/lemon/ssl.conf b/.compose/lemon/ssl.conf new file mode 100644 index 00000000..ad04725e --- /dev/null +++ b/.compose/lemon/ssl.conf @@ -0,0 +1,40 @@ +server { + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + ssl_certificate /etc/nginx/ssl/docker.localhost+1.pem; + ssl_certificate_key /etc/nginx/ssl/docker.localhost+1-key.pem; + server_name _; + location / { + proxy_pass http://localhost:80/; + proxy_redirect off; + proxy_set_header Host $host; + } +} + + +# server { +# listen 443; +# ssl_certificate /etc/nginx/ssl/server.pem; +# ssl_certificate_key /etc/nginx/ssl/server.key; +# server_name fluffychat.docker.localhost; +# root /var/www/fluffychat; +# index index.html; +# location / { +# try_files $uri $uri/ =404; +# } +# } + +# server { +# listen 443; +# ssl_certificate /etc/nginx/ssl/server.pem; +# ssl_certificate_key /etc/nginx/ssl/server.key; +# server_name element.docker.localhost; +# root /var/www/element; +# index index.html; +# location / { +# try_files $uri $uri/ =404; +# add_header Access-Control-Allow-Origin *; +# add_header 'Access-Control-Allow-Credentials' 'true'; +# add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; +# } +# } diff --git a/.compose/ssl/.gitkeep b/.compose/ssl/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/.compose/ssl/60c836bb.0 b/.compose/ssl/60c836bb.0 new file mode 120000 index 00000000..528a59f1 --- /dev/null +++ b/.compose/ssl/60c836bb.0 @@ -0,0 +1 @@ +both.pem \ No newline at end of file diff --git a/.compose/ssl/both.pem b/.compose/ssl/both.pem new file mode 100644 index 00000000..ddc7c905 --- /dev/null +++ b/.compose/ssl/both.pem @@ -0,0 +1,54 @@ +-----BEGIN CERTIFICATE----- +MIIEWzCCAsOgAwIBAgIQPkRKR0crqU1/+t/vU+MMUDANBgkqhkiG9w0BAQsFADCB +gTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSswKQYDVQQLDCJtY2Zs +eUBuaXhvcyAoUGllcnJlICdNY0ZseScgTWFydHkpMTIwMAYDVQQDDClta2NlcnQg +bWNmbHlAbml4b3MgKFBpZXJyZSAnTWNGbHknIE1hcnR5KTAeFw0yNTAxMTYxMDUy +MzlaFw0yNzA0MTYwOTUyMzlaMFYxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVu +dCBjZXJ0aWZpY2F0ZTErMCkGA1UECwwibWNmbHlAbml4b3MgKFBpZXJyZSAnTWNG +bHknIE1hcnR5KTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALp8d8Hs +/lfODAwX1MzrKpvGHLxPlJKyp0c5bX0xJce8HQ4HD7eApo+vnLlzeSTR0pehBNnC +5ftFneW5A5epQYMDVRpKmVN+LDwqdcTt91ewcMLTZObJT3nZ0aj5Es82IxpmBNw/ +Lfu97qTzkjooWDgsmw4M1N168s7MX7gchxXcU5WvgnweFIvWttqmRZFDkzgh0F0g +N/TKoDsS1yDZDVK7L6F9BvKCfSv3mHL7wNJJLgiG5lQkOGu1QL7OIxBVxo5TcyO6 +Eu2WZLd+LDr/vamEPvdu1keVd53cSUPPGgTvjcIwemQ4O7ZkSBtgugZN7VpdQ8vf +9HQvVmaxRbWZ0v8CAwEAAaN5MHcwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoG +CCsGAQUFBwMBMB8GA1UdIwQYMBaAFCfpKUIqE+p6WLK7irGYdXRTX48cMC8GA1Ud +EQQoMCaCEGRvY2tlci5sb2NhbGhvc3SCEiouZG9ja2VyLmxvY2FsaG9zdDANBgkq +hkiG9w0BAQsFAAOCAYEALFT/3ZageziOE2rb/e+R/LFx0Quc7B59pMyBEANCSYHv +JOaDxTeRPRuhvyg9V2DSMnYJyfhVKFpd3yCyXiz2c7O6RlMgW4YR72oK6LchI8+U +YocM4VgrDltP1yAvRnVVZCjF5mlCRi4JFmHrGxJDV0Jkjm0/gikjWmG5cRMT8jMY +fKIIB/gZ5CabQi02C4h/rBjsOA8l/AYkv8LEzQfEm0CJRZZxslO2kyGgWhH1xv5s +dAxnJDN1W7utH45FH1oDdSR9+jWUENKkag7pJ3KJuu41dsL5I1GnZ3UtmyxVTlgz +a1DDs9eXA+TRLBOR0pLebBdm+3NQA70iYLbqJsIY/9dgOdhx9nwFKjF4Lmhgslg/ +Z2zANsvNPJnKadJm0nnk+tA4xS8MkHkH9BKC2Gf44yffwDJWEaOj2eRWyH0/fmvx +ogOXp8UfjY/UlA38TtgzGbVfS3Lf7UgvCu0EeLviiwAFsan11NcUB1OCKiLroIom +9XPZb87v/UsSVwfGI4ba +-----END CERTIFICATE----- +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC6fHfB7P5XzgwM +F9TM6yqbxhy8T5SSsqdHOW19MSXHvB0OBw+3gKaPr5y5c3kk0dKXoQTZwuX7RZ3l +uQOXqUGDA1UaSplTfiw8KnXE7fdXsHDC02TmyU952dGo+RLPNiMaZgTcPy37ve6k +85I6KFg4LJsODNTdevLOzF+4HIcV3FOVr4J8HhSL1rbapkWRQ5M4IdBdIDf0yqA7 +Etcg2Q1Suy+hfQbygn0r95hy+8DSSS4IhuZUJDhrtUC+ziMQVcaOU3MjuhLtlmS3 +fiw6/72phD73btZHlXed3ElDzxoE743CMHpkODu2ZEgbYLoGTe1aXUPL3/R0L1Zm +sUW1mdL/AgMBAAECggEAO0ZaznIk+gXNQH7GrgfFuFPFSHnHEMXmc7YmPhfEGXOK +jK3j6gDjcGJyX2P7yp9C391XbFwNu8uJ/73KDYfIAfuqLjwt9iLxroIUgu7coqu7 +e8GzncO5FlMM2DerKd/cUoTA4LzYQd9CHn4pKYEvYVOUSWf8tRViXicJ+bxfl6uw +orxcxxCs61Tb+eoOfNt/6PyEEAqJUtkL08QOpIR9Q2ANpTfWKNIAPYWYqFmEqSKR +yLBdqhJsoYm2mbNndLPHEavtfnZEiuemqJIKk6ccTuleFagEoRJVGoR8MLsOF4kh +S2OD77gTU8lUy13nMNzjsjl7LkoeoqTWbUE3IRUjEQKBgQDZZoLEaVRMRA29d8iR +59bR9BTGxsiqoCq5sXZqJNBcL+NaPEfM4JWxcjgJP71tplw0arpDmga2zy85oK0H +RDvvSrOT/gV8LeKhQZtqpnWexCMsglOMXI/fXCoT/67SL0huaBIzsU6D3FWmRz4E +DIWETiBj+oAt6yDibqzvn5HKqQKBgQDbmNB0inG9z01/v6zMJK/7Domp1Xo6a/Uk +xfQLQJhCVjV0K7ZYv579szZby1v0VrbnHiKueGP9URZNqnlVA+qac2fXpV7SPVWI +sKH2+zibEU4u8aVYFiuaiDFrQ1MDaZCltJUsAOOPhQ5Ew9Gq96GX950xhTzcwenh +AuW+SLWhZwKBgQCC0wtyQqg11OYn1ENgehFt+uHd1JXBB+1uHXrS2SCBuVepX4kd +ozCxvbg26KKHr4rhCDDaqX/M1tTmauh07PzcPSnfrweB+OLeg2qRPWaeig1YpXy9 +hJ4XnZC8xCph1Y5S0lHRxasn8pmgHFMXgKmAOruHLqGgAFSjrlJnSLElMQKBgDEU +3sKtju6VvwSmmsCmEo9SmIJVLJSSPKCTfhBlx6JMEnZ8rqz3Z1ndDHFH6q2aFBdk +LOxCDFc6IHoLeEMANReAY91XIPJsswlyMUE6tVQzcf4cFJCzo9tORX1r9sn0dlgT +HKRRLouNebr06ZAE+SE2PvQqi4fr75JTS3ZUWgRRAoGAWFJ7M9I7X7Nub9c6l82D +pyQua1hxrYPVe/MhNJXrqAl+qnZStDKy8qi5WiLx8aiD8QY//4/6hCesBU+d+B+7 +/i51gQ8h9/QkB+Fgh7oCYavwndrhtbphKpwowbsHgBet2groGimmc9O4xwCbyoFo +Vy7xtX2X9h0S5SpMPLRKvcc= +-----END PRIVATE KEY----- diff --git a/.compose/ssl/c80bf5cc.0 b/.compose/ssl/c80bf5cc.0 new file mode 120000 index 00000000..44a247b2 --- /dev/null +++ b/.compose/ssl/c80bf5cc.0 @@ -0,0 +1 @@ +rootCA.pem \ No newline at end of file diff --git a/.compose/ssl/docker.localhost+1-key.pem b/.compose/ssl/docker.localhost+1-key.pem new file mode 100644 index 00000000..aa2515b0 --- /dev/null +++ b/.compose/ssl/docker.localhost+1-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC6fHfB7P5XzgwM +F9TM6yqbxhy8T5SSsqdHOW19MSXHvB0OBw+3gKaPr5y5c3kk0dKXoQTZwuX7RZ3l +uQOXqUGDA1UaSplTfiw8KnXE7fdXsHDC02TmyU952dGo+RLPNiMaZgTcPy37ve6k +85I6KFg4LJsODNTdevLOzF+4HIcV3FOVr4J8HhSL1rbapkWRQ5M4IdBdIDf0yqA7 +Etcg2Q1Suy+hfQbygn0r95hy+8DSSS4IhuZUJDhrtUC+ziMQVcaOU3MjuhLtlmS3 +fiw6/72phD73btZHlXed3ElDzxoE743CMHpkODu2ZEgbYLoGTe1aXUPL3/R0L1Zm +sUW1mdL/AgMBAAECggEAO0ZaznIk+gXNQH7GrgfFuFPFSHnHEMXmc7YmPhfEGXOK +jK3j6gDjcGJyX2P7yp9C391XbFwNu8uJ/73KDYfIAfuqLjwt9iLxroIUgu7coqu7 +e8GzncO5FlMM2DerKd/cUoTA4LzYQd9CHn4pKYEvYVOUSWf8tRViXicJ+bxfl6uw +orxcxxCs61Tb+eoOfNt/6PyEEAqJUtkL08QOpIR9Q2ANpTfWKNIAPYWYqFmEqSKR +yLBdqhJsoYm2mbNndLPHEavtfnZEiuemqJIKk6ccTuleFagEoRJVGoR8MLsOF4kh +S2OD77gTU8lUy13nMNzjsjl7LkoeoqTWbUE3IRUjEQKBgQDZZoLEaVRMRA29d8iR +59bR9BTGxsiqoCq5sXZqJNBcL+NaPEfM4JWxcjgJP71tplw0arpDmga2zy85oK0H +RDvvSrOT/gV8LeKhQZtqpnWexCMsglOMXI/fXCoT/67SL0huaBIzsU6D3FWmRz4E +DIWETiBj+oAt6yDibqzvn5HKqQKBgQDbmNB0inG9z01/v6zMJK/7Domp1Xo6a/Uk +xfQLQJhCVjV0K7ZYv579szZby1v0VrbnHiKueGP9URZNqnlVA+qac2fXpV7SPVWI +sKH2+zibEU4u8aVYFiuaiDFrQ1MDaZCltJUsAOOPhQ5Ew9Gq96GX950xhTzcwenh +AuW+SLWhZwKBgQCC0wtyQqg11OYn1ENgehFt+uHd1JXBB+1uHXrS2SCBuVepX4kd +ozCxvbg26KKHr4rhCDDaqX/M1tTmauh07PzcPSnfrweB+OLeg2qRPWaeig1YpXy9 +hJ4XnZC8xCph1Y5S0lHRxasn8pmgHFMXgKmAOruHLqGgAFSjrlJnSLElMQKBgDEU +3sKtju6VvwSmmsCmEo9SmIJVLJSSPKCTfhBlx6JMEnZ8rqz3Z1ndDHFH6q2aFBdk +LOxCDFc6IHoLeEMANReAY91XIPJsswlyMUE6tVQzcf4cFJCzo9tORX1r9sn0dlgT +HKRRLouNebr06ZAE+SE2PvQqi4fr75JTS3ZUWgRRAoGAWFJ7M9I7X7Nub9c6l82D +pyQua1hxrYPVe/MhNJXrqAl+qnZStDKy8qi5WiLx8aiD8QY//4/6hCesBU+d+B+7 +/i51gQ8h9/QkB+Fgh7oCYavwndrhtbphKpwowbsHgBet2groGimmc9O4xwCbyoFo +Vy7xtX2X9h0S5SpMPLRKvcc= +-----END PRIVATE KEY----- diff --git a/.compose/ssl/docker.localhost+1.pem b/.compose/ssl/docker.localhost+1.pem new file mode 100644 index 00000000..e94aaa13 --- /dev/null +++ b/.compose/ssl/docker.localhost+1.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEWzCCAsOgAwIBAgIQPkRKR0crqU1/+t/vU+MMUDANBgkqhkiG9w0BAQsFADCB +gTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSswKQYDVQQLDCJtY2Zs +eUBuaXhvcyAoUGllcnJlICdNY0ZseScgTWFydHkpMTIwMAYDVQQDDClta2NlcnQg +bWNmbHlAbml4b3MgKFBpZXJyZSAnTWNGbHknIE1hcnR5KTAeFw0yNTAxMTYxMDUy +MzlaFw0yNzA0MTYwOTUyMzlaMFYxJzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVu +dCBjZXJ0aWZpY2F0ZTErMCkGA1UECwwibWNmbHlAbml4b3MgKFBpZXJyZSAnTWNG +bHknIE1hcnR5KTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALp8d8Hs +/lfODAwX1MzrKpvGHLxPlJKyp0c5bX0xJce8HQ4HD7eApo+vnLlzeSTR0pehBNnC +5ftFneW5A5epQYMDVRpKmVN+LDwqdcTt91ewcMLTZObJT3nZ0aj5Es82IxpmBNw/ +Lfu97qTzkjooWDgsmw4M1N168s7MX7gchxXcU5WvgnweFIvWttqmRZFDkzgh0F0g +N/TKoDsS1yDZDVK7L6F9BvKCfSv3mHL7wNJJLgiG5lQkOGu1QL7OIxBVxo5TcyO6 +Eu2WZLd+LDr/vamEPvdu1keVd53cSUPPGgTvjcIwemQ4O7ZkSBtgugZN7VpdQ8vf +9HQvVmaxRbWZ0v8CAwEAAaN5MHcwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoG +CCsGAQUFBwMBMB8GA1UdIwQYMBaAFCfpKUIqE+p6WLK7irGYdXRTX48cMC8GA1Ud +EQQoMCaCEGRvY2tlci5sb2NhbGhvc3SCEiouZG9ja2VyLmxvY2FsaG9zdDANBgkq +hkiG9w0BAQsFAAOCAYEALFT/3ZageziOE2rb/e+R/LFx0Quc7B59pMyBEANCSYHv +JOaDxTeRPRuhvyg9V2DSMnYJyfhVKFpd3yCyXiz2c7O6RlMgW4YR72oK6LchI8+U +YocM4VgrDltP1yAvRnVVZCjF5mlCRi4JFmHrGxJDV0Jkjm0/gikjWmG5cRMT8jMY +fKIIB/gZ5CabQi02C4h/rBjsOA8l/AYkv8LEzQfEm0CJRZZxslO2kyGgWhH1xv5s +dAxnJDN1W7utH45FH1oDdSR9+jWUENKkag7pJ3KJuu41dsL5I1GnZ3UtmyxVTlgz +a1DDs9eXA+TRLBOR0pLebBdm+3NQA70iYLbqJsIY/9dgOdhx9nwFKjF4Lmhgslg/ +Z2zANsvNPJnKadJm0nnk+tA4xS8MkHkH9BKC2Gf44yffwDJWEaOj2eRWyH0/fmvx +ogOXp8UfjY/UlA38TtgzGbVfS3Lf7UgvCu0EeLviiwAFsan11NcUB1OCKiLroIom +9XPZb87v/UsSVwfGI4ba +-----END CERTIFICATE----- diff --git a/.compose/ssl/rootCA-key.pem b/.compose/ssl/rootCA-key.pem new file mode 100644 index 00000000..1ae0275a --- /dev/null +++ b/.compose/ssl/rootCA-key.pem @@ -0,0 +1,40 @@ +-----BEGIN PRIVATE KEY----- +MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQDWNSqQesgN+Ej+ +IVbbfcK2LIwM62cZ6dLiUUIaSPK6NwiWYakdPmBuipV3qFMiCtbCcfiUjOA+zUB0 +RUYstLwBPNP8fYOOGf/82lr1170W7ssBbAd0g8nzCWjQYHXWcLcE8moS65ArU9Yd +CPD781L2rvEAK9LFqvtC99ccF+p+7+dV7aqJa1MAb2IoybTno8iSxRun49+1son6 +J8DJpo3wfbJuqJOQ/7qt/eSbtysweORywtxAdxSq4gUBDpFIRVIsDTjR/2e80AVh ++QsNmaW/+uuQ9ySpH4eTYLBW+ZB52vYQMrmd5qtkmF1s2/fqhUdGEOtp5nQfvAbE +DVDc2hoKDFmUlYyPW5fq30dvAay29a7qc4so/+tR/ukMd2ocg/1DNt31Xjvy6nEQ +6k9aLvaph1WuFydYCYJCdMkt47N9KrPAAePjXG90JNqK2d8Ve3BTbLxXwko39JsV +5ELHRmP2Y1TwfWVDejolxK7vcLHEL8j+UMRhe1lYIVDuOOsyYUsCAwEAAQKCAYBr +9I2IFSkfyULYOOsyYXYxI9BNbpIegDZU8wjygFM8QCImz/9QCrDE5Tkg/gcvv/Cu +PIxAKaOWYxEZyBPu0gNySDq6JHOZuUbHIzD2d40Hsr9C7zPup8CuqM5XPlYFBfdn +GdkVwfx9qZneNjRldiMYyeAR6wQltN8+x/N0aCU5ZiTbrJTm/tzs+jWpQsbWezfJ +qGcgvPpw8xMQrNo/hp5AVskHdhQw3oEx0SRWygCNRFA1+jjQkHMtEA3fk3zqxGwS +Awcr8S29xmUMb0rybEC6uus1qyg8gJWELVauhNSLuAqUgK51PxrBp30v9m/vHtOU +KPkMc3iWbNkVCNM6KYVVh1oOrXGermDeKCgMtqa9D7Tv15U4M4RP4CQqLiH8vF0n +mwXnY3thPnw0vdzSupbwhBPF+MNcz6G0rC4UHJhFvkdR4lEwIT+0pt6zh+ohLTlQ +IOjzH+BsRwwTnf6rMSE33kB0bgYvqw/Kw4dJrTerz3UY03ZGJDBE7xUWPPuciwEC +gcEA9uSkoEYNa07AqxFQkd52r5OUmXScqSJFFCm4HPZK9fEWwRw4URTiJtN/m8TX +1hcCF0FBdFff4j9yFljn7F4gPinzKczq2rj5khhITtQUCJ2urGZmtRO7XlF8fmay +PE79SYxrgskbsgq5kAVnCTvdSEDX8jEG3Qn5xq6lWXa3SHaVCS6v/21qbBoi3lab +yYNGalMDND7Ev47WEQyvl0m1tFGxbhGTRmM2qNX4ct5SWxATknxC3koDfku62FmO +3kDLAoHBAN4b4be1culzK9AF1FeSg6/i2T6wqCMj8ZSvesgWjBTtAlCe21lZHUrd +q46rUB9aeiTY4MD6v5lIh8w0Z22XYO1+fvSwbnTinMLweiGfQAeu8PgYvqvklmvz +Rgvxc0xN4XXyrCgWQWnOhaoQ0aX84BvYCGMUKfCP0zrA8umWfM/KyGCL2znU/m20 +RT0NTn7zgG/2ST2cpyF0HQ/8tObeLaJYYptl7sMI5Vq50juV35O6k9HHgdFdA/aQ +TVGbayrRgQKBwQDzYc+7w3LlDpw1xvrS4SfEy0oYwHDS9lp8lufNfSnGKuTQdx45 +J8oMlj/ccX6HqOTBwe1hYGLuqLaxuvDd/KfyP+5ajYwTE3fLAi79rmkVWUPg5Y1o +AcyaHOAJxvj7JK7huxAcvF2V9KaaiAjbfG0WFf4K3TOz4Gqe5nlPqQzi3SrsA18y +AE2BxX4MCfrG+qcGl1C4Rwwy/f6ejg/mpp395O5w39h78b/nTg7+RZWP+Vgh9mcA +tJue+850Ck0hYWMCgcEAz7Ec0a+fw8MJrh01YapE79zdrqx8nVeIGLQ6yQ2kchDq +wD67+IHHTXGZcfCqHJd7bidLi8kuDwTuzzoVmTobzhkiWGb+8tfRJMzAN951fnnN +JQHmklBPhKRY1OQ0H58X/DYvW9Dr3Cfdf5j4ohGj8wWBWjzJtwSWzfMNcvZgweHq +m7VMC3krbaRLtnpR8455hLi15iIteq/cWU3CT7xkydGCa7PWn5Qa/EqU11kfV0H5 +5gl8UC19fjuTwYLmpISBAoHAInOgUXEBO89LF/8+UExf+HV13eTlAmAzWbeh0Ns1 +6/CK+WXnjEZ/IWpXstY2m+fl2//a1/ZJWMB/7+ujG/mWhnGaV7C4xssLWADJmwhs +XCaBVOkZ3W0Bpf+dCxGMNHOydh2nGi0mvUkBUXqn07Hjg7WNB1MZY20pI5zJ2K3w +c6Wtg16IN4kdwSVydsSr5W5EuEBGXQ9FdZa3aObIOLMLl/u7aTqHE2d961usXfwy +mWeoJZC8aGD26fWaJZQkVID9 +-----END PRIVATE KEY----- diff --git a/.compose/ssl/rootCA.pem b/.compose/ssl/rootCA.pem new file mode 100644 index 00000000..405efdbd --- /dev/null +++ b/.compose/ssl/rootCA.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE1DCCAzygAwIBAgIRANvDid3X+qNK0lGY6h4yZH0wDQYJKoZIhvcNAQELBQAw +gYExHjAcBgNVBAoTFW1rY2VydCBkZXZlbG9wbWVudCBDQTErMCkGA1UECwwibWNm +bHlAbml4b3MgKFBpZXJyZSAnTWNGbHknIE1hcnR5KTEyMDAGA1UEAwwpbWtjZXJ0 +IG1jZmx5QG5peG9zIChQaWVycmUgJ01jRmx5JyBNYXJ0eSkwHhcNMjUwMTA2MTEx +OTA1WhcNMzUwMTA2MTExOTA1WjCBgTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3Bt +ZW50IENBMSswKQYDVQQLDCJtY2ZseUBuaXhvcyAoUGllcnJlICdNY0ZseScgTWFy +dHkpMTIwMAYDVQQDDClta2NlcnQgbWNmbHlAbml4b3MgKFBpZXJyZSAnTWNGbHkn +IE1hcnR5KTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBANY1KpB6yA34 +SP4hVtt9wrYsjAzrZxnp0uJRQhpI8ro3CJZhqR0+YG6KlXeoUyIK1sJx+JSM4D7N +QHRFRiy0vAE80/x9g44Z//zaWvXXvRbuywFsB3SDyfMJaNBgddZwtwTyahLrkCtT +1h0I8PvzUvau8QAr0sWq+0L31xwX6n7v51XtqolrUwBvYijJtOejyJLFG6fj37Wy +ifonwMmmjfB9sm6ok5D/uq395Ju3KzB45HLC3EB3FKriBQEOkUhFUiwNONH/Z7zQ +BWH5Cw2Zpb/665D3JKkfh5NgsFb5kHna9hAyuZ3mq2SYXWzb9+qFR0YQ62nmdB+8 +BsQNUNzaGgoMWZSVjI9bl+rfR28BrLb1rupziyj/61H+6Qx3ahyD/UM23fVeO/Lq +cRDqT1ou9qmHVa4XJ1gJgkJ0yS3js30qs8AB4+Ncb3Qk2orZ3xV7cFNsvFfCSjf0 +mxXkQsdGY/ZjVPB9ZUN6OiXEru9wscQvyP5QxGF7WVghUO446zJhSwIDAQABo0Uw +QzAOBgNVHQ8BAf8EBAMCAgQwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU +J+kpQioT6npYsruKsZh1dFNfjxwwDQYJKoZIhvcNAQELBQADggGBADjS6r6BdyEb +jNrElHc+yUA55RuC/CMZFmdsYAAGZGZUEL/cfZbKHf7ObwJqcdVREWxARc/qmSLd +iAduppcxDmxFoENxr/tu4LQb9v9ySwzTVJsxiL1bi4QPG5fBMX5qEDI1ejmku92F +qa4N3pWyVM21Ze8pmOiNr/4cwwu85Dlb6LqS+jjAkvKkvCWrxKxj+HifvefsgRFO ++H7V7oH1RfMccWDhBBgv9Q8ywm2ztEXeU3Bodg6UruLXE/8Dl36avIIeIPpTknKr +/qdSqzdEHECyeLkqo5i+gxTYM4dwb7fW4gUMHofC+9vL8bMnbgZUdXccA9SRWJbQ +Aw7bBE9MlnmlBIAxLmg0KQ7KmCH0ZXucbEeex4WeOwyIY6+LJP9neetbqDRmVHm1 +zeAyjq3Uk9xRhPn6loDtYQUsZmLYJzXOZeE+C7U/r7TM8f/XBiWcQWkQX+LGptJ9 +/BB2E0Yc6MF7KyUrkNfzLUiOGI1OJaSM83WaYkhvFuj6RYnCtPOGOw== +-----END CERTIFICATE----- diff --git a/.compose/synapse/homeserver.yaml b/.compose/synapse/homeserver.yaml new file mode 100644 index 00000000..9d28741a --- /dev/null +++ b/.compose/synapse/homeserver.yaml @@ -0,0 +1,216 @@ +# 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 +# +# For more information on how to configure Synapse, including a complete accounting of +# each option, go to docs/usage/configuration/config_documentation.md or +# https://matrix-org.github.io/synapse/latest/usage/configuration/config_documentation.html +server_name: "docker.localhost" +public_baseurl: "https://matrix.docker.localhost/" + +pid_file: /data/homeserver.pid + +# For test, these lines are dropped: +#federation_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' +# - '169.254.0.0/16' +# - '::1/128' +# - 'fe80::/64' +# - 'fc00::/7' + +# For test, no TLS +#tls_certificate_path: "/data/homeserver.tls.crt" +#tls_private_key_path: "/data/homeserver.tls.key" +#tls_dh_params_path: "/data/homeserver.tls.dh" +#no_tls: False +#tls_fingerprints: [] + +listeners: + # Unsecure HTTP listener, + # For when matrix traffic passes through loadbalancer that unwraps TLS. + - port: 8008 + tls: false + type: http + x_forwarded: true + resources: + - names: [client] + compress: true + - names: [federation] + compress: false + + # Replication Endpoints + # The HTTP replication port + - port: 8100 + tls: false + type: http + resources: + - names: [replication] + + # Metrics end-point + - port: 9000 + tls: false + type: metrics + + ## Test: no tls + # Main HTTPS listener + # For when matrix traffic is sent directly to synapse. + #- port 8448 + # bind_addresses: + # - '0.0.0.0' + # - '::' + # type: http + # tls: true + # x_forwarded: false + # resources: + # - names: [client] + # compress: true + # - names: [federation] + # compress: false + +database: + name: sqlite3 + args: + database: /data/homeserver.db + + cp_min: 5 + cp_max: 10 + +# Number of events to cache in memory +event_cache_size: '10K' + +log_config: "/data/matrix.docker.localhost.log.config" +media_store_path: /data/media_store +uploads_path: /data/uploads +max_upload_size: '100M' +max_image_pixels: '32M' +dynamic_thumbnails: false +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 +url_preview_enabled: true +url_preview_ip_range_blacklist: + - '192.168.254.0/24' +max_spider_size: '10M' +url_preview_accept_language: + +enable_registration: false +account_validity: + +bcrypt_rounds: 12 +allow_guest_access: False + +trusted_third_party_id_servers: + - matrix.org + - vector.im + - riot.im + +enable_metrics: false + +report_stats: false + +macaroon_secret_key: "i8dF@4#7uLt~ZJC@m@HqxfXt+-Y^rvI5yF3CC;8LbXwNLWO9YM" +form_secret: ":m_kP~38:lPnlfO2S8lhSrMRy8T52~dT=e35X+jCMHNz-pxIoZ" + +expire_access_token: False + +## Signing key +signing_key_path: "/data/matrix.docker.localhost.signing.key" +# To rotate signing keys +old_signing_keys: {} +key_refresh_interval: '1d' # 1 Day. + +# Trusted servers to download signing keys from +# +# If matrix.org is really allowed here: +suppress_key_server_warning: true +trusted_key_servers: + - server_name: 'matrix.org' + accept_keys_insecurely: true + #- server_name: "twake_root_server" + # verify_keys: + # "ed25519:auto": "aabbccddeeff..." + +password_config: + enabled: false + +## SSO +# Old fashion: prefer separated oidc_providers files +oidc_providers: + - idp_id: twake + idp_name: Connect with Twake + enabled: true + issuer: "https://auth.docker.localhost" + client_id: 'matrix1' + client_secret: 'matrix1' + scopes: ['openid', 'profile', 'email'] + + discover: true + # Test only + #authorization_endpoint: "https://auth.docker.localhost/oauth2/authorize" + #token_endpoint: "https://auth.docker.localhost/oauth2/token" + #userinfo_endpoint: "https://auth.docker.localhost/oauth2/userinfo" + #jwks_uri: "https://auth.docker.localhost/oauth2/jwks" + + backchannel_logout_enabled: true + backchannel_logout_is_soft: true + + user_profile_method: 'userinfo_endpoint' + user_mapping_provider: + config: + subject_claim: 'sub' + localpart_template: '{{ user.preferred_username }}' + display_name_template: '{{ user.name }}' + +# Whether to allow non server admin to create groups on this server +enable_group_creation: true + +user_directory: + search_all_users: true + +e2e_key_export: true +encryption_enabled: true + +# FOR TEST ONLY +accept_keys_insecurely: true +federation_verify_certificates: false + +# TODO: identity_server integration +# * invite_client_location +# * account_threepid_delegates +default_identity_server: https://tom.docker.localhost + +### Matrix Synapse's scalability part - using workers +instance_map: + main: # The main instance + host: synapse + port: 8100 # THIS MUST BE THE REPLICATION PORT + +enable_media_repo: true + +# Custom templates for SSO redirect, among others. +templates: + custom_template_directory: /data/templates + +# Used for auto-registrating the admin. NOTE : this string MUST NOT be shared anywhere! +registration_shared_secret: "bH_8Ot;-4INv:yfXHZ1.ul_XP2KuL5xC-R4x#.9G6.+6J0^-V#" diff --git a/.compose/synapse/matrix.docker.localhost.log.config b/.compose/synapse/matrix.docker.localhost.log.config new file mode 100644 index 00000000..bd0e59fb --- /dev/null +++ b/.compose/synapse/matrix.docker.localhost.log.config @@ -0,0 +1,28 @@ +version: 1 + +formatters: + precise: + format: '%(asctime)s - %(name)s - %(lineno)d - %(levelname)s - %(request)s - %(message)s' + +handlers: + console: + class: logging.StreamHandler + formatter: precise + +loggers: + # This is just here so we can leave `loggers` in the config regardless of whether + # we configure other loggers below (avoid empty yaml dict error). + _placeholder: + level: "INFO" + + synapse.storage.SQL: + # beware: increasing this to DEBUG will make synapse log sensitive + # information such as access tokens. + level: INFO + +root: + level: INFO + handlers: [console] + +disable_existing_loggers: false + diff --git a/.compose/synapse/matrix.docker.localhost.signing.key b/.compose/synapse/matrix.docker.localhost.signing.key new file mode 100644 index 00000000..e069ab99 --- /dev/null +++ b/.compose/synapse/matrix.docker.localhost.signing.key @@ -0,0 +1 @@ +ed25519 a_hLKN b8fuZvGNEydpm5oS8Djmn4vXQhreRdiN46cBtxY88u0 diff --git a/.compose/synapse/templates/.gitkeep b/.compose/synapse/templates/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/.compose/synapse/wellknownclient.conf b/.compose/synapse/wellknownclient.conf new file mode 100644 index 00000000..f44626d7 --- /dev/null +++ b/.compose/synapse/wellknownclient.conf @@ -0,0 +1,5 @@ +{ + "m.homeserver": { + "base_url": "https://matrix.docker.localhost" + } +} diff --git a/.compose/synapse/wellknownserver.conf b/.compose/synapse/wellknownserver.conf new file mode 100644 index 00000000..76076bbe --- /dev/null +++ b/.compose/synapse/wellknownserver.conf @@ -0,0 +1,3 @@ +{ + "m.server": "matrix.docker.localhost:443" +} diff --git a/.compose/tom/.gitkeep b/.compose/tom/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..40ab7a7e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,25 @@ +.direnv/ +.git/ +.github/ +docs/ +node_modules/ + +.envrc +.gitlab-ci.yml +**/Dockerfile +**/.*md +docker-compose.yml +flake.lock +flake.nix + +**/*.db +**/*.db-shm +**/*.db-wal + +**/*.map +packages/**/example/*.js* + +**/dist/ +**/node_modules/ +**/.nx/ +**/coverage/ diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..3550a30f --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore index 259784db..fb768904 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,15 @@ packages/*/example/*.js* *.map .nx/ packages/matrix-identity-server/matrix-server/synapse-data + +## direnv +.direnv/ + +## compose related +.compose/**/*.env +.compose/synapse/media_store/ + +# ignore sqlite files +**/*.db +**/*.db-shm +**/*.db-wal diff --git a/DOCKER-VARIABLES.md b/DOCKER-VARIABLES.md deleted file mode 100644 index fdec1f89..00000000 --- a/DOCKER-VARIABLES.md +++ /dev/null @@ -1,38 +0,0 @@ -# Docker varibales for ToM server - - * `BASE_URL`: Base URL of the servce. Example: `https://tom.company.com` - * `CRON_SERVICE`: Boolean (1 or 0): enable cron tasks or not - * `CROWDSEC_URI`: optional URI of local CrowdSec server - * `CROWDSEC_KEY`: CrowdSec API key _(required if `CROWDSEC_URI` is set) - * `DATABASE_ENGINE`: `sqlite` or `pg` - * `DATABASE_HOST`: - * case `pg`: hostname - * case `sqlite`: database path - * `DATABASE_NAME`: [pg] - * `DATABASE_USER`: [pg] - * `DATABASE_PASSWORD`: [pg] - * `LDAP_BASE`: base of LDAP where users are stored. Example: `dc=example,dc=com` - * `LDAP_FILTER`: LDAP filter to find users. Example: `(objectClass=person)` - * `LDAP_USER`: full LDAP `dn` used to connect - * `LDAP_PASSWORD`: LDAP password - * `LDAP_URI`: example: `ldaps://ldap.company.com` - * `JITSI_BASE_URL`: example `https://jitsi.linagora.com` - * 5 strings to set if Jitsi is strictly reserved for Twake users: - * `JITSI_JWT_ALGORITHM`: example: `HS256` - * `JITSI_JWT_ISSUER`: - * `JITSI_SECRET`: - * `JITSI_PREFERRED_DOMAIN`: - * `JITSI_USE_JWT`: - * `MATRIX_SERVER`: Matrix server. Example: `matrix.company.com` - * `MATRIX_DATABASE_ENGINE`: `sqlite` or `pg` - * `MATRIX_DATABASE_HOST`: - * case `pg`: hostname - * case `sqlite`: database path - * `MATRIX_DATABASE_NAME`: [pg] - * `MATRIX_DATABASE_PASSWORD`: [pg] - * `MATRIX_DATABASE_USER`: [pg] - * `OIDC_ISSUER`: Lemon URL. Example: `https://auth.company.com` - * `SERVER_NAME`: Matrix "server name" _(ie domain)_. Example: `company.com` - * `TEMPLATE_DIR`: Local path to templates dir (mail template). - * `RATE_LIMITING_WINDOW`: How long to remember requests for, in milliseconds. - * `RATE_LIMITING_NB_REQUESTS`: How many requests to allow. diff --git a/Dockerfile b/Dockerfile index 4fd337d6..c456119c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Base for final image -FROM debian:bookworm-slim as node-minimal +FROM debian:bookworm-slim AS node-minimal RUN apt update && \ apt -y dist-upgrade && \ @@ -9,7 +9,7 @@ RUN apt update && \ rm -rf /var/lib/apt/lists/* # Temporary image to build app -FROM debian:bookworm-slim as builder +FROM debian:bookworm-slim AS builder RUN apt update && \ apt -y dist-upgrade && \ @@ -31,14 +31,14 @@ COPY landing /usr/src/app/landing #COPY node_modules ./node_modules/ # Build and clean - RUN npm install RUN npm run build -- --skip-nx-cache RUN rm -rf node_modules */*/node_modules RUN npm install --production --ignore-scripts +RUN npm explore sqlite3 -- npm install --production RUN npm cache clean --force -FROM node-minimal as tom-server +FROM node-minimal AS tom-server ENV BASE_URL= \ CRON_SERVICE= \ diff --git a/README.md b/README.md index 7d10bdc2..f1fb220f 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,6 @@ - - -

Website • @@ -38,12 +35,7 @@ Here is the architecture principle: REST API Endpoints documentation is available on https://linagora.github.io/ToM-server/ -[Try it with docker](#twake-chat-docker) - -## Scripts - -* `npm run build`: build all packages -* `npm run test`: test all packages +[Try it with docker](./docker.md) ## Modules @@ -64,74 +56,15 @@ REST API Endpoints documentation is available on https://linagora.github.io/ToM- [Matrix specification](https://spec.matrix.org/latest/server-server-api/#server-discovery) * [@twake/retry-promise](packages/retry-promise): simple module extending javascript Promise with retry strategy -## Twake-Chat docker - -This repository provides different docker images. The main is [Tom Server](./Dockerfile) itself. Here are its environment variables: - -* Required: - * `BASE_URL`: Public URL - * Database: - * `DATABASE_ENGINE` _(`pg` or `sqlite`)_ - * `DATABASE_HOST` _(path for `sqlite`)_ - * `DATABASE_NAME` - * `DATABASE_USER` - * `DATABASE_PASSWORD` - * `DATABASE_SSL` - * `OIDC_ISSUER`: URL of SSO server - * LDAP service: - * `LDAP_BASE` - * `LDAP_FILTER` - * `LDAP_USER` - * `LDAP_PASSWORD` - * `LDAP_URI` - * Matrix server: - * `SERVER_NAME` _(same value than in Matrix's homeserver.yaml)_ - * `MATRIX_SERVER` _(real Matrix server)_ - * `TEMPLATE_DIR` _(default: `node_modules/@twake/server/templates`)_ -* Recommended: - * `ADDITIONAL_FEATURES`: set true to have all search features; false for a public instance - * Cron service: - * `CRON_SERVICE` _(default: true)_: enable cron tasks - * `PEPPER_CRON` _(default: `9 1 * * *`)_ - * `UPDATE_USERS_CRON` _(default: `*/15 * * * *`)_ - * `UPDATE_FEDERATED_IDENTITY_HASHES_CRON` _(default: `3 3 * * *`)_ - * Logs: - * `LOG_TRANSPORTS`: set to `Console` - * `LOG_LEVEL`: default to "error", possible values: "error", "warn", "info", "http", "verbose", "debug", "silly" - * `TRUSTED_PROXIES`: IP list of server allowed to set `X-Frowarded-For` header - * Rate limits _(see [express-rate-limit](https://www.npmjs.com/package/express-rate-limit))_: - * `RATE_LIMITING_WINDOW` - * `RATE_LIMITING_NB_REQUESTS` -* Optional: - * `FEDERATED_IDENTITY_SERVICES`: list of federated identity services - * Use a CrowdSec service: - * `CROWDSEC_URI` - * `CROWDSEC_KEY` - * Add Jitsi into metadata: - * `JITSI_BASE_URL` - * `JITSI_JWT_ALGORITHM` - * `JITSI_JWT_ISSUER` - * `JITSI_SECRET` - * `JITSI_PREFERRED_DOMAIN` - * `JITSI_USE_JWT` - * Matrix database _(for automatic channels)_: - * `MATRIX_DATABASE_ENGINE` - * `MATRIX_DATABASE_HOST` - * `MATRIX_DATABASE_NAME` - * `MATRIX_DATABASE_PASSWORD` - * `MATRIX_DATABASE_SSL` - * `MATRIX_DATABASE_USER` - * Opensearch features: - * `OPENSEARCH_CA_CERT_PATH` - * `OPENSEARCH_HOST` - * `OPENSEARCH_IS_ACTIVATED` - * `OPENSEARCH_MAX_RETRIES` - * `OPENSEARCH_NUMBER_OF_SHARDS` - * `OPENSEARCH_NUMBER_OF_REPLICAS` - * `OPENSEARCH_PASSWORD` - * `OPENSEARCH_SSL` - * `OPENSEARCH_USER` - * `OPENSEARCH_WAIT_FOR_ACTIVE_SHARDS` +## Requirements + +- [ ] Node >=18 + +## Commands + +* `npm run build`: build all packages +* `npm run test`: test all packages +* `node ./server.mjs`: run the server ## Copyright and license diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100755 index 00000000..2f98d20b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,122 @@ +# File : docker-compose.yml +# License : AGPL-3.0-or-later +# Author : Pierre 'McFly' Marty +# Date : 16.01.2025 +# Last Modified Date: 27.01.2025 +# Last Modified By : Pierre 'McFly' Marty + +services: + auth: + image: yadd/lemonldap-ng-full + volumes: + - ./.compose/lemon/lmConf-1.json:/var/lib/lemonldap-ng/conf/lmConf-1.json + - ./.compose/lemon/ssl.conf:/etc/nginx/sites-enabled/0000default.conf + - ./.compose/lemon/root.conf:/etc/nginx/sites-enabled/root.conf + - ./.compose/synapse/wellknownserver.conf:/var/www/matrix-server.json + - ./.compose/synapse/wellknownclient.conf:/var/www/matrix-client.json + - ./.compose/ssl:/etc/nginx/ssl + - ./.compose/lemon/lemon.db:/db/lemon.db + environment: + - SSODOMAIN=docker.localhost + - PORTAL=https://auth.docker.localhost + - LOGLEVEL=debug + - LOGGER=stderr + - USERLOGGER=stderr + deploy: + mode: replicated + replicas: 1 + restart_policy: + condition: on-failure + networks: + frontend: + aliases: + - auth + + synapse: + image: matrixdotorg/synapse + restart: unless-stopped + env_file: + - path: .compose/.env + required: true + volumes: + - ./.compose/synapse:/data + - ./.compose/ssl:/etc/ssl/certs + depends_on: + auth: + condition: service_started + networks: + frontend: + aliases: + - synapse + + tom: + build: + context: . + args: + TOM_EXTRA_DEPS: sqlite3 + volumes: + - ./.compose/tom:/opt/twake/db/ + - ./.compose/synapse:/opt/synapse/db/ + depends_on: + synapse: + condition: service_started + ports: + - 3000:3000 + networks: + frontend: + aliases: + - tom.server + environment: + - BASE_URL=https://tom.docker.localhost + - DATABASE_ENGINE=sqlite + - DATABASE_HOST=/opt/twake/db/tom.db + - MATRIX_SERVER=matrix.docker.localhost + - MATRIX_DATABASE_ENGINE=sqlite + - MATRIX_DATABASE_HOST=/opt/synapse/db/homeserver.db + - OIDC_ISSUER=https://auth.docker.localhost + - SERVER_NAME=docker.localhost + - USERDB_ENGINE=sqlite + - LOG_LEVEL=silly + - LOG_TRANSPORTS=Console + - TEMPLATE_DIR=/usr/src/app/packages/tom-server/templates + - TRUSTED_PROXIES=uniquelocal + - NODE_TLS_REJECT_UNAUTHORIZED=0 + + chat: + image: linagora/twake-web + volumes: + - ./.compose/chat/config.json:/usr/share/nginx/html/web/config.json + - ./.compose/chat/default.conf.template:/etc/nginx/templates/default.conf.template + - ./.compose/ssl:/etc/nginx/ssl + ports: + - 6868:6868 + environment: + - TWAKECHAT_LISTEN_PORT=6868 + networks: + - frontend + + haproxy: + image: haproxy:2.6-bookworm + ports: + - 443:443 + volumes: + - ./.compose/haproxy:/usr/local/etc/haproxy:ro + - ./.compose/ssl/both.pem:/etc/ssl/certs/both.pem + sysctls: + - net.ipv4.ip_unprivileged_port_start=0 + depends_on: + - auth + - chat + - synapse + - tom + networks: + frontend: + aliases: + - auth.docker.localhost + - chat.docker.localhost + - matrix.docker.localhost + - tom.docker.localhost + +networks: + frontend: + name: frontend diff --git a/docker.md b/docker.md index 24fd9084..9e8785fd 100644 --- a/docker.md +++ b/docker.md @@ -1,12 +1,116 @@ -# Use Tawe-on-Matrix server with docker +# Serve Tawe-on-Matrix as a container Image are published in docker hub: - * [The ToM Server itself](https://hub.docker.com/r/linagora/tom-server) - * [The Federated Identity Service](https://hub.docker.com/r/linagora/tom-federated-identity-service) -## The ToM server image +- [The ToM Server itself](https://hub.docker.com/r/linagora/tom-server) +- [The Federated Identity Service](https://hub.docker.com/r/linagora/tom-federated-identity-service) -### Synopsis +## ToM Variables + +| Status | Description | +| ------------ | ------------------------------------------------------------ | +| **required** | Server cannot starts without | +| recommended | Server can start without, but we advise to use it | +| *optional* | Use it to turn on specific features, depending to your needs | + +--- + +Set of variables used to configure ToM features and behavior. + +| Name | Description | Default | Status | +| --------------------------------------- | ------------------------------------------------------------------------------------- | -------------------------------------- | ------------ | +| `BASE_URL` | Public URL. `https://tom.example.com` | `none` | **required** | +| `DATABASE_ENGINE` | The Database engine to use *(`pg` for PostgreSQL or `sqlite`)* | `none` | **required** | +| `DATABASE_HOST` | `pg`: URL to connect to, `sqlite`: path to the .db file | `none` | **required** | +| `DATABASE_NAME` | Name of the databse to use *(for `pg` only)* | `none` | **required** | +| `DATABASE_USER` | User that will connect to the database *(for `pg` only)* | `none` | **required** | +| `DATABASE_PASSWORD` | User's password *(for `pg` only)* | `none` | **required** | +| `DATABASE_SSL` | Wether or not to use SSL for db connection *(for `pg` only)* | `false` | **required** | +| `OIDC_ISSUER` | URL of SSO server | `none` | **required** | +| `LDAP_BASE` | Example: `dc=example,dc=com` | `none` | recommended | +| `LDAP_FILTER` | Example: `(objectClass=person)` | `none` | recommended | +| `LDAP_USER` | full LDAP `dn` used to connect | `none` | recommended | +| `LDAP_PASSWORD` | Password corresponding to the `dn` | `none` | recommended | +| `LDAP_URI` | URL of the LDAP directory, e.g. `ldaps://ldap.company.com` | `none` | recommended | +| `TEMPLATE_DIR` | Path to folder containing mail templates | `node_modules/@twake/server/templates` | recommended | +| `RATE_LIMITING_WINDOW` | How long to remember requests for, in milliseconds. | `600000` | recommended | +| `RATE_LIMITING_NB_REQUESTS` | How many requests to allow. | `100` | recommended | +| `ADDITIONAL_FEATURES` | Set true to have all search features | `false` | recommended | +| `FEDERATED_IDENTITY_SERVICES` | List of federated identity services | `[]` | recommended | +| `CRON_SERVICE` | Enable cron tasks | `false` | *optional* | +| `PEPPER_CRON` | When should the pepper (i.e hash salt) be updated *(cron syntax)* | `9 1 * * *` | *optional* | +| `UPDATE_USERS_CRON` | When should the users data be refreshed *(cron syntax)* | `*/10 * * * *` | *optional* | +| `UPDATE_FEDERATED_IDENTITY_HASHES_CRON` | When should the users hashed data should be sent to federation server *(cron syntax)* | `*/10 * * * *` | *optional* | +| `USERDB_ENGINE` | The database engine used to store user data. *(`ldap` or `sqlite`)* | `ldap` | *optional* | +| `LOG_TRANSPORTS` | | `Console` | *optional* | +| `LOG_LEVEL` | Possible values: `error`, `warn`, `info`, `http`, `verbose`, `debug`, `silly` | `Console` | *optional* | +| `TRUSTED_PROXIES` | IP list of server allowed to set `X-Frowarded-For` header | `[]` | *optional* | + +### Matrix + +Configure the interconnection of ToM and a Matrix server. + +| Name | Description | Default | Status | +| -------------------------- | ------------------------------------------------------------------------------------------- | -------- | ------------ | +| `SERVER_NAME` | same value than in Matrix's homeserver.yaml | `none` | **required** | +| `MATRIX_SERVER` | Example: `matrix.company.com` | `none` | **required** | +| `MATRIX_DATABASE_ENGINE` | The Database engine used by the Matrix server *(`pg` for PostgreSQL or `sqlite`)* | `none` | *optional* | +| `MATRIX_DATABASE_HOST` | `pg`: URL to connect to the Matrix PGSQL instance, `sqlite`: path to the homeserver.db file | `none` | *optional* | +| `MATRIX_DATABASE_NAME` | Name of the databse to use *(for `pg` only)* | `none` | *optional* | +| `MATRIX_DATABASE_USER` | User that will connect to the database *(for `pg` only)* | `none` | *optional* | +| `MATRIX_DATABASE_PASSWORD` | User's password *(for `pg` only)* | `none` | *optional* | +| `MATRIX_DATABASE_SSL` | Wether or not to use SSL for db connection *(for `pg` only)* | `false` | *optional* | + +### Jitsi + +Tells ToM to also add Jitsi metadata to the `.well-known`. + +| Name | Description | Default | Status | +| ------------------------ | ----------- | -------- | ---------- | +| `JITSI_BASE_URL` | | `none` | *optional* | +| `JITSI_JWT_ALGORITHM` | | `none` | *optional* | +| `JITSI_JWT_ISSUER` | | `none` | *optional* | +| `JITSI_SECRET` | | `none` | *optional* | +| `JITSI_PREFERRED_DOMAIN` | | `none` | *optional* | +| `JITSI_USE_JWT` | | `false` | *optional* | + +### Crowdsec + +To secure your installation with [the help of the crowd](https://github.com/crowdsecurity/crowdsec). + +| Name | Description | Default | Status | +| -------------- | --------------------------------- | ------- | ---------- | +| `CROWDSEC_URI` | API URI to use | `none` | *optional* | +| `CROWDSEC_KEY` | The secret key for authentication | `none` | *optional* | + +### OpenSearch + +| Name | Description | Default | Status | +| ----------------------------------- | ------------------------------------------ | ------- | ---------- | +| `OPENSEARCH_IS_ACTIVATED` | Enable or not the OpenSearch integration | `false` | *optional* | +| `OPENSEARCH_HOST` | URI of the OpenSearch instance | `none` | *optional* | +| `OPENSEARCH_MAX_RETRIES` | | `none` | *optional* | +| `OPENSEARCH_NUMBER_OF_SHARDS` | | `none` | *optional* | +| `OPENSEARCH_NUMBER_OF_REPLICAS` | | `none` | *optional* | +| `OPENSEARCH_USER` | The user that connects to OpenSearch | `none` | *optional* | +| `OPENSEARCH_PASSWORD` | | `none` | *optional* | +| `OPENSEARCH_WAIT_FOR_ACTIVE_SHARDS` | Must ToM wait for active shards | `none` | *optional* | +| `OPENSEARCH_SSL` | Wether to use SSL to connect to OpenSearch | `false` | *optional* | +| `OPENSEARCH_CA_CERT_PATH` | Path of the CA to use for SSL termination | `none` | *optional* | + +## Use the ToM Image + +The ToM server is made to be configured with environment variables, allowing a +fast, easy and flexible configuration - especially for container deployments. + +To make the server fits your needs, simply add/remove the corresponding +variables. Though, please note that some remain required. One can use [the +table above](#tom-variables) detailling all available vars. + +In the following example, ToM is deployed with its additional features, on the +'example.com' domain, using a PostgreSQL instance for it's own database +storage, another is used for storing Synpase data, and an LDAP directory is +used to store user information (such as nickname, auth credentials, or email): ```shell $ docker run -d -p 3000:3000 \ @@ -36,3 +140,90 @@ $ docker run -d -p 3000:3000 \ -e RATE_LIMITING_WINDOW=10 -e RATE_LIMITING_NB_REQUESTS=100 linagora/tom-server +``` + +## Start a Lightweight Local Environment + +To facilitate your debuts we provide a [`docker-compose.yml`](./docker-compose.yml) +featuring a complete environment to run and try ToM. + +This environment uses `docker.localhost` as default domain, and stores its +rootCA in [`./.compose/ssl/`](./.compose/ssl/). Feel free to use another domain, +but remember to update the configurations (in the `.compose` folder) +accordingly. + +### `/etc/hosts` + +```conf +127.0.0.1 docker.localhost # base domain +127.0.0.1 auth.docker.localhost # SSO +127.0.0.1 matrix.docker.localhost # matrix server +127.0.0.1 tom.docker.localhost # tom server +127.0.0.1 chat.docker.localhost # matrix client (Twake Chat) +``` + +### Kickstart + +```bash +## Uncomment the following to create your own certificate +# pushd .compose/ssl/ +# mkcert -install +# mkcert docker.localhost *.docker.localhost +# cat docker.localhost+1.pem docker.localhost+1-key.pem > both.pem +# popd + +## Add your Timezone, UID and GID to the synapse container +pushd .compose/ +echo "TZ=$(timedatectl show | grep -Poh '(?<=^Timezone=).*')" | tee .env +echo "UID=$(id -u)" | tee -a .env +echo "GID=$(id -g)" | tee -a .env + +## OR - manual edition +# cp .env.template .env +# $EDITOR .env +popd + +## Initialize LemonLDAP::NG (SSO) database +pushd .compose/lemon +./init-db.sh + +## Add more users +# ./create-user.sh 'nickname' 'givenname' 'password' +popd +``` +--- + +*NixOS manages the rootCA installation differently ; https://search.nixos.org/options?channel=24.11&show=security.pki.certificates&from=0&size=50&sort=relevance&type=packages&query=certificates \ +Be sure to install yours accordingly.* + +```nix + # rootCA + security.pki.certificates = [ + '' + docker.localhost + ================ + -----BEGIN CERTIFICATE----- + + content of .compose/rootCA.pem or yours + + -----END CERTIFICATE----- + '' + ]; +``` + +--- + +```bash +## Fire up! +docker-compose up # -d +# docker compose up # -d +``` + +### Default users + +| Name | Nickname | Password | +| ------------- | -------- | -------- | +| Doctor Who | dwho | dwho | +| R. Tyler | rtyler | rtyler | +| Jar Jar Binks | jbinks | jbinks | + diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..38e472f3 --- /dev/null +++ b/flake.lock @@ -0,0 +1,60 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1737022245, + "narHash": "sha256-AkDUWBsc4WJXGSRFb7UUDwecDAaybFj1YvvDZhY4V7g=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "1bda1e50be0d0ae1ecd4f4b707c680bc3ec6c22b", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..fff2cb91 --- /dev/null +++ b/flake.nix @@ -0,0 +1,53 @@ +{ + description = "tom-server dev env"; + + inputs = { + flake-utils.url = "github:numtide/flake-utils"; + nixpkgs.url = "github:NixOS/nixpkgs"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachSystem [ "x86_64-linux" ] (system: + let + pkgs = import nixpkgs { + inherit system; + + config.allowUnfree = true; + }; + in + { + devShell = with pkgs; mkShell rec { + # ENV_VAR_NAME = "value"; + + # Packages to install + buildInputs = [ + ## Global Requirements + nodejs + typescript + + ## tools + lazydocker + sqlite # For local db support + + # Local SSL tooling + mkcert # Cert local toolchain + openssl + + ## dev tools + npm-check + npm-check-updates + npm-lockfile-fix + typescript-language-server + ]; + + # Run this at start + shellHook = '' + echo + echo "node version: $(node -v)" + echo "npm version: $(npm -v)" + echo + ''; + }; + } + ); +} diff --git a/packages/federated-identity-service/src/__testData__/db/init-llng-db.sh b/packages/federated-identity-service/src/__testData__/db/init-llng-db.sh index 80d7a094..c8415d9e 100644 --- a/packages/federated-identity-service/src/__testData__/db/init-llng-db.sh +++ b/packages/federated-identity-service/src/__testData__/db/init-llng-db.sh @@ -16,64 +16,64 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E CREATE DATABASE $DATABASE; EOSQL psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$DATABASE" <<-EOSQL - CREATE TABLE $TABLE ( + CREATE TABLE IF NOT EXISTS $TABLE ( cfgNum integer not null primary key, data text ); GRANT ALL PRIVILEGES ON TABLE $TABLE TO $USER; - CREATE TABLE $PTABLE ( + CREATE TABLE IF NOT EXISTS $PTABLE ( id varchar(64) not null primary key, a_session jsonb ); - CREATE INDEX i_p__session_kind ON psessions ((a_session ->> '_session_kind')); - CREATE INDEX i_p__httpSessionType ON psessions ((a_session ->> '_httpSessionType')); - CREATE INDEX i_p__session_uid ON psessions ((a_session ->> '_session_uid')); - CREATE INDEX i_p_ipAddr ON psessions ((a_session ->> 'ipAddr')); - CREATE INDEX i_p__whatToTrace ON psessions ((a_session ->> '_whatToTrace')); + CREATE INDEX IF NOT EXISTS i_p__session_kind ON psessions ((a_session ->> '_session_kind')); + CREATE INDEX IF NOT EXISTS i_p__httpSessionType ON psessions ((a_session ->> '_httpSessionType')); + CREATE INDEX IF NOT EXISTS i_p__session_uid ON psessions ((a_session ->> '_session_uid')); + CREATE INDEX IF NOT EXISTS i_p_ipAddr ON psessions ((a_session ->> 'ipAddr')); + CREATE INDEX IF NOT EXISTS i_p__whatToTrace ON psessions ((a_session ->> '_whatToTrace')); GRANT ALL PRIVILEGES ON TABLE $PTABLE TO $USER; - CREATE UNLOGGED TABLE $STABLE ( + CREATE UNLOGGED TABLE IF NOT EXISTS $STABLE ( id varchar(64) not null primary key, a_session jsonb ); - CREATE INDEX i_s__whatToTrace ON sessions ((a_session ->> '_whatToTrace')); - CREATE INDEX i_s__session_kind ON sessions ((a_session ->> '_session_kind')); - CREATE INDEX i_s__utime ON sessions ((cast (a_session ->> '_utime' as bigint))); - CREATE INDEX i_s_ipAddr ON sessions ((a_session ->> 'ipAddr')); - CREATE INDEX i_s__httpSessionType ON sessions ((a_session ->> '_httpSessionType')); - CREATE INDEX i_s_user ON sessions ((a_session ->> 'user')); + CREATE INDEX IF NOT EXISTS i_s__whatToTrace ON sessions ((a_session ->> '_whatToTrace')); + CREATE INDEX IF NOT EXISTS i_s__session_kind ON sessions ((a_session ->> '_session_kind')); + CREATE INDEX IF NOT EXISTS i_s__utime ON sessions ((cast (a_session ->> '_utime' as bigint))); + CREATE INDEX IF NOT EXISTS i_s_ipAddr ON sessions ((a_session ->> 'ipAddr')); + CREATE INDEX IF NOT EXISTS i_s__httpSessionType ON sessions ((a_session ->> '_httpSessionType')); + CREATE INDEX IF NOT EXISTS i_s_user ON sessions ((a_session ->> 'user')); GRANT ALL PRIVILEGES ON TABLE $STABLE TO $USER; - CREATE UNLOGGED TABLE $SAMLTABLE ( + CREATE UNLOGGED TABLE IF NOT EXISTS $SAMLTABLE ( id varchar(64) not null primary key, a_session jsonb ); - CREATE INDEX i_a__session_kind ON $SAMLTABLE ((a_session ->> '_session_kind')); - CREATE INDEX i_a__utime ON $SAMLTABLE ((cast(a_session ->> '_utime' as bigint))); - CREATE INDEX i_a_ProxyID ON $SAMLTABLE ((a_session ->> 'ProxyID')); - CREATE INDEX i_a__nameID ON $SAMLTABLE ((a_session ->> '_nameID')); - CREATE INDEX i_a__assert_id ON $SAMLTABLE ((a_session ->> '_assert_id')); - CREATE INDEX i_a__art_id ON $SAMLTABLE ((a_session ->> '_art_id')); - CREATE INDEX i_a__saml_id ON $SAMLTABLE ((a_session ->> '_saml_id')); + CREATE INDEX IF NOT EXISTS i_a__session_kind ON $SAMLTABLE ((a_session ->> '_session_kind')); + CREATE INDEX IF NOT EXISTS i_a__utime ON $SAMLTABLE ((cast(a_session ->> '_utime' as bigint))); + CREATE INDEX IF NOT EXISTS i_a_ProxyID ON $SAMLTABLE ((a_session ->> 'ProxyID')); + CREATE INDEX IF NOT EXISTS i_a__nameID ON $SAMLTABLE ((a_session ->> '_nameID')); + CREATE INDEX IF NOT EXISTS i_a__assert_id ON $SAMLTABLE ((a_session ->> '_assert_id')); + CREATE INDEX IF NOT EXISTS i_a__art_id ON $SAMLTABLE ((a_session ->> '_art_id')); + CREATE INDEX IF NOT EXISTS i_a__saml_id ON $SAMLTABLE ((a_session ->> '_saml_id')); GRANT ALL PRIVILEGES ON TABLE $SAMLTABLE TO $USER; - CREATE UNLOGGED TABLE $OIDCTABLE ( + CREATE UNLOGGED TABLE IF NOT EXISTS $OIDCTABLE ( id varchar(64) not null primary key, a_session jsonb ); - CREATE INDEX i_o__session_kind ON $OIDCTABLE ((a_session ->> '_session_kind')); - CREATE INDEX i_o__utime ON $OIDCTABLE ((cast(a_session ->> '_utime' as bigint ))); + CREATE INDEX IF NOT EXISTS i_o__session_kind ON $OIDCTABLE ((a_session ->> '_session_kind')); + CREATE INDEX IF NOT EXISTS i_o__utime ON $OIDCTABLE ((cast(a_session ->> '_utime' as bigint ))); GRANT ALL PRIVILEGES ON TABLE $OIDCTABLE TO $USER; - CREATE UNLOGGED TABLE $CASTABLE ( + CREATE UNLOGGED TABLE IF NOT EXISTS $CASTABLE ( id varchar(64) not null primary key, a_session jsonb ); - CREATE INDEX i_c__session_kind ON $CASTABLE ((a_session ->> '_session_kind')); - CREATE INDEX i_c__utime ON $CASTABLE ((cast(a_session ->> '_utime' as bigint))); - CREATE INDEX i_c__cas_id ON $CASTABLE ((a_session ->> '_cas_id')); - CREATE INDEX i_c_pgtIou ON $CASTABLE ((a_session ->> 'pgtIou')); + CREATE INDEX IF NOT EXISTS i_c__session_kind ON $CASTABLE ((a_session ->> '_session_kind')); + CREATE INDEX IF NOT EXISTS i_c__utime ON $CASTABLE ((cast(a_session ->> '_utime' as bigint))); + CREATE INDEX IF NOT EXISTS i_c__cas_id ON $CASTABLE ((a_session ->> '_cas_id')); + CREATE INDEX IF NOT EXISTS i_c_pgtIou ON $CASTABLE ((a_session ->> 'pgtIou')); GRANT ALL PRIVILEGES ON TABLE $CASTABLE TO $USER; EOSQL diff --git a/packages/matrix-client-server/src/__testData__/pg/install/docker-entrypoint-initdb.d/init-user-db.sh b/packages/matrix-client-server/src/__testData__/pg/install/docker-entrypoint-initdb.d/init-user-db.sh index 2d5d404b..18d7e2db 100644 --- a/packages/matrix-client-server/src/__testData__/pg/install/docker-entrypoint-initdb.d/init-user-db.sh +++ b/packages/matrix-client-server/src/__testData__/pg/install/docker-entrypoint-initdb.d/init-user-db.sh @@ -7,6 +7,6 @@ PASSWORD=${PG_PASSWORD:-twake} psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL CREATE USER $USER PASSWORD '$PASSWORD'; - CREATE DATABASE $DATABASE; + CREATE DATABASE IF NOT EXISTS $DATABASE; GRANT ALL PRIVILEGES ON DATABASE $DATABASE TO $USER; EOSQL diff --git a/packages/matrix-identity-server/src/cron/check-quota.test.ts b/packages/matrix-identity-server/src/cron/check-quota.test.ts index 90eacfc9..4495b19e 100644 --- a/packages/matrix-identity-server/src/cron/check-quota.test.ts +++ b/packages/matrix-identity-server/src/cron/check-quota.test.ts @@ -35,7 +35,7 @@ beforeAll(async () => { try { await new Promise((resolve, reject) => { testdb.run( - 'CREATE TABLE local_media_repository (user_id varchar(64), media_length int)', + 'CREATE TABLE IF NOT EXISTS local_media_repository (user_id varchar(64), media_length int)', (e: unknown) => { if (e !== null) reject( diff --git a/packages/matrix-identity-server/src/db/sql/_createTables.ts b/packages/matrix-identity-server/src/db/sql/_createTables.ts index 02ce5ff4..79fa8e80 100644 --- a/packages/matrix-identity-server/src/db/sql/_createTables.ts +++ b/packages/matrix-identity-server/src/db/sql/_createTables.ts @@ -19,7 +19,9 @@ function createTables( .then((count) => { /* istanbul ignore else */ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (!count) { - db.rawQuery(`CREATE TABLE ${table}(${tables[table]})`) + db.rawQuery( + `CREATE TABLE IF NOT EXISTS ${table}(${tables[table]})` + ) // eslint-disable-next-line @typescript-eslint/promise-function-async .then(() => Promise.all( @@ -32,7 +34,7 @@ function createTables( >((index) => db .rawQuery( - `CREATE INDEX i_${table}_${index} ON ${table} (${index})` + `CREATE INDEX IF NOT EXISTS i_${table}_${index} ON ${table} (${index})` ) .catch((e) => { /* istanbul ignore next */ diff --git a/packages/tom-server/src/application-server/__testData__/build-userdb.ts b/packages/tom-server/src/application-server/__testData__/build-userdb.ts index 64858e84..db29a8c3 100644 --- a/packages/tom-server/src/application-server/__testData__/build-userdb.ts +++ b/packages/tom-server/src/application-server/__testData__/build-userdb.ts @@ -15,7 +15,7 @@ export const buildUserDB = (conf: Partial): Promise => { const matrixDb = new sqlite3.Database(conf.matrix_database_host) matrixDb.run( - 'CREATE TABLE users (name text, desactivated text, admin integer)', + 'CREATE TABLE IF NOT EXISTS users (name text, desactivated text, admin integer)', (err) => { if (err != null) { reject(err) @@ -32,7 +32,7 @@ export const buildUserDB = (conf: Partial): Promise => { export const deleteUserDB = (conf: Partial): Promise => { return new Promise((resolve, reject) => { const matrixDb = new sqlite3.Database(conf.matrix_database_host) - matrixDb.run('DROP TABLE users', (err) => { + matrixDb.run('DROP TABLE IF EXISTS users', (err) => { if (err != null) { reject(err) } else { diff --git a/packages/tom-server/src/identity-server/__testData__/buildUserDB.ts b/packages/tom-server/src/identity-server/__testData__/buildUserDB.ts index 39540bb9..784cc9bd 100644 --- a/packages/tom-server/src/identity-server/__testData__/buildUserDB.ts +++ b/packages/tom-server/src/identity-server/__testData__/buildUserDB.ts @@ -10,7 +10,7 @@ interface Config { let created = false const createQuery = - 'CREATE TABLE users (uid varchar(8), mobile varchar(12), mail varchar(32), sn varchar(32))' + 'CREATE TABLE IF NOT EXISTS users (uid varchar(8), mobile varchar(12), mail varchar(32), sn varchar(32))' const insertQuery = "INSERT INTO users VALUES('dwho', '33612345678', 'dwho@example.com', 'Dwho')" @@ -22,7 +22,7 @@ const buildUserDB = (conf: Config, recreate?: boolean): Promise => { const matrixDb = new sqlite3.Database(conf.matrix_database_host) matrixDb.run( - 'CREATE TABLE users (name text, desactivated text, admin integer)', + 'CREATE TABLE IF NOT EXISTS users (name text, desactivated text, admin integer)', (err) => { if (err != null) { reject(err) diff --git a/packages/tom-server/src/invitation-api/tests/controller.test.ts b/packages/tom-server/src/invitation-api/tests/controller.test.ts index a7474094..48bacd13 100644 --- a/packages/tom-server/src/invitation-api/tests/controller.test.ts +++ b/packages/tom-server/src/invitation-api/tests/controller.test.ts @@ -53,7 +53,10 @@ app.use(bodyParser.json()) app.use(bodyParser.urlencoded({ extended: true })) app.use( router( - { matrix_server: 'http://localhost:789', base_url: 'http://localhost' } as unknown as Config, + { + matrix_server: 'http://localhost:789', + base_url: 'http://localhost' + } as unknown as Config, dbMock as unknown as TwakeDB, authenticatorMock, loggerMock as unknown as TwakeLogger diff --git a/packages/tom-server/src/search-engine-api/__testData__/db/init-llng-db.sh b/packages/tom-server/src/search-engine-api/__testData__/db/init-llng-db.sh index 80d7a094..c8415d9e 100644 --- a/packages/tom-server/src/search-engine-api/__testData__/db/init-llng-db.sh +++ b/packages/tom-server/src/search-engine-api/__testData__/db/init-llng-db.sh @@ -16,64 +16,64 @@ psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-E CREATE DATABASE $DATABASE; EOSQL psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$DATABASE" <<-EOSQL - CREATE TABLE $TABLE ( + CREATE TABLE IF NOT EXISTS $TABLE ( cfgNum integer not null primary key, data text ); GRANT ALL PRIVILEGES ON TABLE $TABLE TO $USER; - CREATE TABLE $PTABLE ( + CREATE TABLE IF NOT EXISTS $PTABLE ( id varchar(64) not null primary key, a_session jsonb ); - CREATE INDEX i_p__session_kind ON psessions ((a_session ->> '_session_kind')); - CREATE INDEX i_p__httpSessionType ON psessions ((a_session ->> '_httpSessionType')); - CREATE INDEX i_p__session_uid ON psessions ((a_session ->> '_session_uid')); - CREATE INDEX i_p_ipAddr ON psessions ((a_session ->> 'ipAddr')); - CREATE INDEX i_p__whatToTrace ON psessions ((a_session ->> '_whatToTrace')); + CREATE INDEX IF NOT EXISTS i_p__session_kind ON psessions ((a_session ->> '_session_kind')); + CREATE INDEX IF NOT EXISTS i_p__httpSessionType ON psessions ((a_session ->> '_httpSessionType')); + CREATE INDEX IF NOT EXISTS i_p__session_uid ON psessions ((a_session ->> '_session_uid')); + CREATE INDEX IF NOT EXISTS i_p_ipAddr ON psessions ((a_session ->> 'ipAddr')); + CREATE INDEX IF NOT EXISTS i_p__whatToTrace ON psessions ((a_session ->> '_whatToTrace')); GRANT ALL PRIVILEGES ON TABLE $PTABLE TO $USER; - CREATE UNLOGGED TABLE $STABLE ( + CREATE UNLOGGED TABLE IF NOT EXISTS $STABLE ( id varchar(64) not null primary key, a_session jsonb ); - CREATE INDEX i_s__whatToTrace ON sessions ((a_session ->> '_whatToTrace')); - CREATE INDEX i_s__session_kind ON sessions ((a_session ->> '_session_kind')); - CREATE INDEX i_s__utime ON sessions ((cast (a_session ->> '_utime' as bigint))); - CREATE INDEX i_s_ipAddr ON sessions ((a_session ->> 'ipAddr')); - CREATE INDEX i_s__httpSessionType ON sessions ((a_session ->> '_httpSessionType')); - CREATE INDEX i_s_user ON sessions ((a_session ->> 'user')); + CREATE INDEX IF NOT EXISTS i_s__whatToTrace ON sessions ((a_session ->> '_whatToTrace')); + CREATE INDEX IF NOT EXISTS i_s__session_kind ON sessions ((a_session ->> '_session_kind')); + CREATE INDEX IF NOT EXISTS i_s__utime ON sessions ((cast (a_session ->> '_utime' as bigint))); + CREATE INDEX IF NOT EXISTS i_s_ipAddr ON sessions ((a_session ->> 'ipAddr')); + CREATE INDEX IF NOT EXISTS i_s__httpSessionType ON sessions ((a_session ->> '_httpSessionType')); + CREATE INDEX IF NOT EXISTS i_s_user ON sessions ((a_session ->> 'user')); GRANT ALL PRIVILEGES ON TABLE $STABLE TO $USER; - CREATE UNLOGGED TABLE $SAMLTABLE ( + CREATE UNLOGGED TABLE IF NOT EXISTS $SAMLTABLE ( id varchar(64) not null primary key, a_session jsonb ); - CREATE INDEX i_a__session_kind ON $SAMLTABLE ((a_session ->> '_session_kind')); - CREATE INDEX i_a__utime ON $SAMLTABLE ((cast(a_session ->> '_utime' as bigint))); - CREATE INDEX i_a_ProxyID ON $SAMLTABLE ((a_session ->> 'ProxyID')); - CREATE INDEX i_a__nameID ON $SAMLTABLE ((a_session ->> '_nameID')); - CREATE INDEX i_a__assert_id ON $SAMLTABLE ((a_session ->> '_assert_id')); - CREATE INDEX i_a__art_id ON $SAMLTABLE ((a_session ->> '_art_id')); - CREATE INDEX i_a__saml_id ON $SAMLTABLE ((a_session ->> '_saml_id')); + CREATE INDEX IF NOT EXISTS i_a__session_kind ON $SAMLTABLE ((a_session ->> '_session_kind')); + CREATE INDEX IF NOT EXISTS i_a__utime ON $SAMLTABLE ((cast(a_session ->> '_utime' as bigint))); + CREATE INDEX IF NOT EXISTS i_a_ProxyID ON $SAMLTABLE ((a_session ->> 'ProxyID')); + CREATE INDEX IF NOT EXISTS i_a__nameID ON $SAMLTABLE ((a_session ->> '_nameID')); + CREATE INDEX IF NOT EXISTS i_a__assert_id ON $SAMLTABLE ((a_session ->> '_assert_id')); + CREATE INDEX IF NOT EXISTS i_a__art_id ON $SAMLTABLE ((a_session ->> '_art_id')); + CREATE INDEX IF NOT EXISTS i_a__saml_id ON $SAMLTABLE ((a_session ->> '_saml_id')); GRANT ALL PRIVILEGES ON TABLE $SAMLTABLE TO $USER; - CREATE UNLOGGED TABLE $OIDCTABLE ( + CREATE UNLOGGED TABLE IF NOT EXISTS $OIDCTABLE ( id varchar(64) not null primary key, a_session jsonb ); - CREATE INDEX i_o__session_kind ON $OIDCTABLE ((a_session ->> '_session_kind')); - CREATE INDEX i_o__utime ON $OIDCTABLE ((cast(a_session ->> '_utime' as bigint ))); + CREATE INDEX IF NOT EXISTS i_o__session_kind ON $OIDCTABLE ((a_session ->> '_session_kind')); + CREATE INDEX IF NOT EXISTS i_o__utime ON $OIDCTABLE ((cast(a_session ->> '_utime' as bigint ))); GRANT ALL PRIVILEGES ON TABLE $OIDCTABLE TO $USER; - CREATE UNLOGGED TABLE $CASTABLE ( + CREATE UNLOGGED TABLE IF NOT EXISTS $CASTABLE ( id varchar(64) not null primary key, a_session jsonb ); - CREATE INDEX i_c__session_kind ON $CASTABLE ((a_session ->> '_session_kind')); - CREATE INDEX i_c__utime ON $CASTABLE ((cast(a_session ->> '_utime' as bigint))); - CREATE INDEX i_c__cas_id ON $CASTABLE ((a_session ->> '_cas_id')); - CREATE INDEX i_c_pgtIou ON $CASTABLE ((a_session ->> 'pgtIou')); + CREATE INDEX IF NOT EXISTS i_c__session_kind ON $CASTABLE ((a_session ->> '_session_kind')); + CREATE INDEX IF NOT EXISTS i_c__utime ON $CASTABLE ((cast(a_session ->> '_utime' as bigint))); + CREATE INDEX IF NOT EXISTS i_c__cas_id ON $CASTABLE ((a_session ->> '_cas_id')); + CREATE INDEX IF NOT EXISTS i_c_pgtIou ON $CASTABLE ((a_session ->> 'pgtIou')); GRANT ALL PRIVILEGES ON TABLE $CASTABLE TO $USER; EOSQL diff --git a/packages/tom-server/src/vault-api/__testData__/buildTokenTable.ts b/packages/tom-server/src/vault-api/__testData__/buildTokenTable.ts index e678adc1..631c65fe 100644 --- a/packages/tom-server/src/vault-api/__testData__/buildTokenTable.ts +++ b/packages/tom-server/src/vault-api/__testData__/buildTokenTable.ts @@ -14,7 +14,7 @@ const buildTokenTable = (conf: Config): Promise => { const matrixDbManager = new sqlite3.Database(conf.matrix_database_host) dbManager.run( - 'CREATE TABLE matrixTokens (id varchar(64) primary key, data text)', + 'CREATE TABLE IF NOT EXISTS matrixTokens (id varchar(64) primary key, data text)', () => dbManager.run( `INSERT INTO matrixTokens VALUES('${token.value}', '${JSON.stringify( @@ -22,7 +22,7 @@ const buildTokenTable = (conf: Config): Promise => { )}')`, () => { dbManager.run( - 'CREATE TABLE users (uid varchar(8), mobile varchar(12), mail varchar(32))', + 'CREATE TABLE IF NOT EXISTS users (uid varchar(8), mobile varchar(12), mail varchar(32))', () => { dbManager.close((err) => { /* istanbul ignore if */ @@ -40,7 +40,7 @@ const buildTokenTable = (conf: Config): Promise => { ) matrixDbManager.run( - 'CREATE TABLE users (uid varchar(8), name varchar(32), mobile varchar(12), mail varchar(32))' + 'CREATE TABLE IF NOT EXISTS users (uid varchar(8), name varchar(32), mobile varchar(12), mail varchar(32))' ) }) } diff --git a/server.mjs b/server.mjs index db642a30..f47bd6f1 100644 --- a/server.mjs +++ b/server.mjs @@ -77,7 +77,7 @@ let conf = { update_federated_identity_hashes_cron: process.env.UPDATE_FEDERATED_IDENTITY_HASHES_CRON || '*/10 * * * *', update_users_cron: process.env.UPDATE_USERS_CRON || '*/10 * * * *', - userdb_engine: 'ldap', + userdb_engine: process.env.USERDB_ENGINE || 'ldap', sms_api_key: process.env.SMS_API_KEY, sms_api_login: process.env.SMS_API_LOGIN, sms_api_url: process.env.SMS_API_URL,