Compare commits
168 Commits
v1.140.0rc
...
joriks/con
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dbbdf1a4a9 | ||
|
|
2f360de3b6 | ||
|
|
d934837b48 | ||
|
|
5d02267d85 | ||
|
|
1e5b073fd8 | ||
|
|
0bc1f9c2d1 | ||
|
|
af3af0c8e4 | ||
|
|
4798dd1f6b | ||
|
|
cea9329e0b | ||
|
|
53b94eff58 | ||
|
|
997fe30087 | ||
|
|
b18761b3e3 | ||
|
|
d56e1bedad | ||
|
|
b1c9c5a078 | ||
|
|
d4a52d31ef | ||
|
|
ec743b9165 | ||
|
|
6472d30e6a | ||
|
|
0cfe4b3db9 | ||
|
|
0a2c2086c8 | ||
|
|
406a790cf5 | ||
|
|
eba2753781 | ||
|
|
27135d9a28 | ||
|
|
127e0b1cd7 | ||
|
|
2b08f5c6bd | ||
|
|
8e1d22c6f7 | ||
|
|
2d56f81d05 | ||
|
|
c36c0278b0 | ||
|
|
66bc80eddf | ||
|
|
01d05e40a9 | ||
|
|
1cef415af7 | ||
|
|
13ea03ccd6 | ||
|
|
ea54afb1c3 | ||
|
|
39f758c07c | ||
|
|
0690f7fc55 | ||
|
|
d63a58462f | ||
|
|
e5622a483c | ||
|
|
ec76921ecb | ||
|
|
bbd4880371 | ||
|
|
0d73df5c10 | ||
|
|
b78ae32b4e | ||
|
|
763c1d320c | ||
|
|
0a5099cd24 | ||
|
|
932aeca8c6 | ||
|
|
e58f3ffe2f | ||
|
|
4b72b03d00 | ||
|
|
69d0da4e32 | ||
|
|
ac47193ff0 | ||
|
|
aed01c8b93 | ||
|
|
84d04e9001 | ||
|
|
d79788c953 | ||
|
|
22fcbbfe5e | ||
|
|
e48e9ba41b | ||
|
|
438d7fa75a | ||
|
|
2f04eb2797 | ||
|
|
4ac5bd96e8 | ||
|
|
e023fd563f | ||
|
|
70c04c54b1 | ||
|
|
4d2f0090e9 | ||
|
|
cc8fa83fcc | ||
|
|
da19eb18be | ||
|
|
58802ef961 | ||
|
|
1629d91b68 | ||
|
|
9b0fc37f2d | ||
|
|
9349614a16 | ||
|
|
20eb0de9b5 | ||
|
|
4fe0c9eb1c | ||
|
|
82008faff8 | ||
|
|
02dc1cf13a | ||
|
|
45557de936 | ||
|
|
4bd7d5fa26 | ||
|
|
ab805cd9ad | ||
|
|
d48a316a55 | ||
|
|
d8a19849e8 | ||
|
|
ff59e6a85c | ||
|
|
8b2acd1454 | ||
|
|
a35dcd33b1 | ||
|
|
f56760604d | ||
|
|
089645458f | ||
|
|
3f8100bda2 | ||
|
|
6afcf0fc92 | ||
|
|
9e7a889418 | ||
|
|
ed3e3df538 | ||
|
|
eb537f087f | ||
|
|
e0452b89f2 | ||
|
|
a26e54860b | ||
|
|
d01310d9e9 | ||
|
|
6b0e658440 | ||
|
|
e03421b050 | ||
|
|
e79d63c88d | ||
|
|
2440c70630 | ||
|
|
25f8fba5a3 | ||
|
|
bea99ee6a1 | ||
|
|
96778c68d6 | ||
|
|
53fbf82f4e | ||
|
|
546ce01e0d | ||
|
|
6bc3ff60c7 | ||
|
|
511f8b626b | ||
|
|
53ecf93da1 | ||
|
|
aa657705e4 | ||
|
|
659471703f | ||
|
|
d6c296d184 | ||
|
|
5414d470f5 | ||
|
|
e34448600e | ||
|
|
153a340a6a | ||
|
|
3cfe24a32c | ||
|
|
c747fca2e8 | ||
|
|
ce2b433bf7 | ||
|
|
07fe7906ad | ||
|
|
f618f8a44f | ||
|
|
893a346212 | ||
|
|
23a837c194 | ||
|
|
a41a655819 | ||
|
|
2c7a57f9d9 | ||
|
|
2d9f82e18a | ||
|
|
58964e4063 | ||
|
|
62e45eebbf | ||
|
|
2a909302cf | ||
|
|
a5fa7653fa | ||
|
|
b6a8d989f4 | ||
|
|
a209536849 | ||
|
|
442da5fbdd | ||
|
|
353543a780 | ||
|
|
6744c080d7 | ||
|
|
63b9c8d3a6 | ||
|
|
388dcb1e6c | ||
|
|
280d50cd4f | ||
|
|
47ca664311 | ||
|
|
4573aceeeb | ||
|
|
c9c7960390 | ||
|
|
7e8f993a84 | ||
|
|
83198702f5 | ||
|
|
e00008186b | ||
|
|
fb592b6c98 | ||
|
|
1c9c8186b1 | ||
|
|
c5ca02b3d0 | ||
|
|
eb10b04865 | ||
|
|
39641482ef | ||
|
|
eedd86766d | ||
|
|
3a8bebff88 | ||
|
|
c2bf291a0d | ||
|
|
a8cc43dfac | ||
|
|
3ae448a183 | ||
|
|
b87c85a87d | ||
|
|
3a9194e652 | ||
|
|
3b3abcc273 | ||
|
|
d599ab6249 | ||
|
|
96c56177a8 | ||
|
|
a079c9bf0d | ||
|
|
7fe1148f44 | ||
|
|
02845e7e3a | ||
|
|
9a0ba7696e | ||
|
|
bb79dc1351 | ||
|
|
2835f033b4 | ||
|
|
1481108afa | ||
|
|
318b66fa2a | ||
|
|
b5881cab45 | ||
|
|
175ee86e6d | ||
|
|
3242aa9af2 | ||
|
|
9280882cb9 | ||
|
|
cd0cb18d94 | ||
|
|
e5765ac4af | ||
|
|
2a34815d48 | ||
|
|
ced3cb281a | ||
|
|
a00ce82e46 | ||
|
|
3cf68de825 | ||
|
|
d7a8670cf5 | ||
|
|
4163c25449 | ||
|
|
d2d36126f7 |
1
synapse_topology/.gitignore
vendored
Normal file
1
synapse_topology/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
config_dir
|
||||
40
synapse_topology/__init__.py
Executable file
40
synapse_topology/__init__.py
Executable file
@@ -0,0 +1,40 @@
|
||||
#! python
|
||||
import argparse
|
||||
import os.path as path
|
||||
import sys
|
||||
|
||||
from synapse_topology.server import Server
|
||||
from synapse_topology.model import Model
|
||||
|
||||
from twisted.internet import endpoints, reactor
|
||||
from twisted.web.server import Site
|
||||
|
||||
from twisted.logger import (
|
||||
eventsFromJSONLogFile,
|
||||
textFileLogObserver,
|
||||
globalLogPublisher,
|
||||
)
|
||||
|
||||
globalLogPublisher.addObserver(textFileLogObserver(sys.stdout))
|
||||
|
||||
parser = argparse.ArgumentParser(description="Synapse configuration util")
|
||||
parser.add_argument(
|
||||
"config_dir",
|
||||
metavar="CONFIG_DIR",
|
||||
type=str,
|
||||
help="Path the directory containing synapse's configuration files.",
|
||||
)
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if not path.isdir(args.config_dir):
|
||||
print("'{}' is not a directory.".format(args.config_dir))
|
||||
exit(1)
|
||||
|
||||
|
||||
model = Model(args.config_dir)
|
||||
|
||||
server = Server(model)
|
||||
|
||||
server.app.run("localhost", 8888)
|
||||
18
synapse_topology/docs/README.rst
Normal file
18
synapse_topology/docs/README.rst
Normal file
@@ -0,0 +1,18 @@
|
||||
Backend
|
||||
=======
|
||||
::
|
||||
|
||||
Make sure you have synapse and klein installed in your pip env
|
||||
```
|
||||
./__init__.py config_dir
|
||||
```
|
||||
|
||||
Frontend
|
||||
========
|
||||
Start the Backend and then
|
||||
|
||||
.. code:: bash
|
||||
|
||||
cd view/webui
|
||||
yarn install
|
||||
yarn watch
|
||||
95
synapse_topology/model/__init__.py
Normal file
95
synapse_topology/model/__init__.py
Normal file
@@ -0,0 +1,95 @@
|
||||
import yaml
|
||||
import subprocess
|
||||
|
||||
from os import mkdir
|
||||
from os.path import abspath, join, exists, isdir
|
||||
|
||||
from synapse.config.homeserver import HomeServerConfig
|
||||
|
||||
from .constants import CONFIG_LOCK, CONFIG_LOCK_DATA, DATA_SUBDIR, SERVER_NAME
|
||||
from .errors import BaseConfigInUseError, ConfigNotFoundError, ServernameNotSetError
|
||||
from .config import create_config
|
||||
from .util import is_subpath
|
||||
|
||||
from synapse.config import find_config_files
|
||||
|
||||
|
||||
class Model:
|
||||
"""
|
||||
The Model brokers modification of the config file and signing keys in the config
|
||||
directory.
|
||||
"""
|
||||
|
||||
def __init__(self, config_dir):
|
||||
self.config_dir = abspath(config_dir)
|
||||
self.data_dir = abspath(join(self.config_dir, DATA_SUBDIR))
|
||||
if not isdir(self.config_dir):
|
||||
mkdir(self.config_dir)
|
||||
|
||||
if not isdir(self.data_dir):
|
||||
mkdir(self.data_dir)
|
||||
|
||||
def get_config(self, config_path):
|
||||
"""
|
||||
Retrieves a config from the config directory. Any path can be provided
|
||||
but it must be a subdirectory of self.config_dir
|
||||
|
||||
Args:
|
||||
config_path (str): path to the config
|
||||
|
||||
Returns:
|
||||
dict: the yaml parse of the config file
|
||||
"""
|
||||
conf_path = abspath(join(self.config_dir, config_path))
|
||||
|
||||
if not is_subpath(self.config_dir, conf_path):
|
||||
raise FileNotFoundError()
|
||||
|
||||
with open(conf_path, "r") as f:
|
||||
return yaml.safe_load(f)
|
||||
|
||||
def write_config(self, config):
|
||||
"""
|
||||
Given a config generates a templated config from synapse and writes it
|
||||
out to the config dir. It will raise an exception if the config in
|
||||
the config directory is in use.
|
||||
|
||||
Args:
|
||||
config (dict): The configuration to template out.
|
||||
"""
|
||||
if self.config_in_use():
|
||||
raise BaseConfigInUseError()
|
||||
|
||||
for conf_name, conf in create_config(
|
||||
self.config_dir, self.data_dir, config
|
||||
).items():
|
||||
with open(abspath(join(self.config_dir, conf_name)), "w") as f:
|
||||
f.write(conf)
|
||||
|
||||
def config_in_use(self):
|
||||
"""
|
||||
Checks if we set whether the config is in use. If it was set up by the system
|
||||
but synapse wasn't launched yet we will have set this to False. However if
|
||||
it's not present we assume someone else has set up synapse before so we assume
|
||||
the config is in use.
|
||||
"""
|
||||
config = {}
|
||||
config_files = find_config_files([self.config_dir])
|
||||
for config_file in config_files:
|
||||
with open(config_file) as stream:
|
||||
config.update(yaml.safe_load(stream))
|
||||
|
||||
if not config:
|
||||
return False
|
||||
|
||||
print(config.get(CONFIG_LOCK))
|
||||
return config.get(CONFIG_LOCK, True)
|
||||
|
||||
def generate_secret_key(self, server_name):
|
||||
if self.config_in_use():
|
||||
raise BaseConfigInUseError()
|
||||
|
||||
signing_key_path = join(self.config_dir, server_name + ".signing.key")
|
||||
subprocess.run(["generate_signing_key.py", "-o", signing_key_path])
|
||||
with open(signing_key_path, "r") as f:
|
||||
return f.read()
|
||||
66
synapse_topology/model/config.py
Normal file
66
synapse_topology/model/config.py
Normal file
@@ -0,0 +1,66 @@
|
||||
from os.path import join
|
||||
|
||||
import yaml
|
||||
|
||||
from synapse.config.database import DatabaseConfig
|
||||
from synapse.config.homeserver import HomeServerConfig
|
||||
from synapse.config.logger import LoggingConfig
|
||||
from synapse.config.server import ServerConfig
|
||||
from synapse.config.tls import TlsConfig
|
||||
|
||||
|
||||
def create_config(config_dir_path, data_dir_path, conf):
|
||||
server_name = conf["server_name"]
|
||||
del conf["server_name"]
|
||||
|
||||
server_config_in_use = conf["server_config_in_use"]
|
||||
del conf["server_config_in_use"]
|
||||
|
||||
database_conf = conf["database"]
|
||||
del conf["database"]
|
||||
|
||||
if database_conf["name"] == "sqlite3":
|
||||
database_conf.setdefault(
|
||||
"args", {"database": join(data_dir_path, "homeserver.db")}
|
||||
)
|
||||
|
||||
base_configs = [ServerConfig, DatabaseConfig, TlsConfig]
|
||||
|
||||
# Generate configs for all the ones we didn't cover explicitely
|
||||
uninitialized_configs = [
|
||||
x for x in list(HomeServerConfig.__bases__) if x not in base_configs
|
||||
]
|
||||
|
||||
class BaseConfig(*base_configs):
|
||||
pass
|
||||
|
||||
class AdvancedConfig(*uninitialized_configs):
|
||||
pass
|
||||
|
||||
config_args = {
|
||||
"config_dir_path": config_dir_path,
|
||||
"data_dir_path": data_dir_path,
|
||||
"server_name": server_name,
|
||||
**conf,
|
||||
"database_conf": database_conf,
|
||||
"generate_secrets": True,
|
||||
}
|
||||
|
||||
base_config = BaseConfig()
|
||||
advanced_config = AdvancedConfig()
|
||||
|
||||
base_config_text = base_config.generate_config(**config_args)
|
||||
advanced_config_text = advanced_config.generate_config(**config_args)
|
||||
|
||||
config = {}
|
||||
config.update(yaml.safe_load(base_config_text))
|
||||
config.update(yaml.safe_load(advanced_config_text))
|
||||
|
||||
base_config.generate_missing_files(config, config_dir_path)
|
||||
advanced_config.generate_missing_files(config, config_dir_path)
|
||||
|
||||
return {
|
||||
"homeserver_basic_config.yaml": base_config_text
|
||||
+ "\n\nserver_config_in_use: {}".format(server_config_in_use),
|
||||
"homeserver_advanced_config.yaml": advanced_config_text,
|
||||
}
|
||||
22
synapse_topology/model/constants.py
Normal file
22
synapse_topology/model/constants.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# Paths
|
||||
DATA_SUBDIR = "data"
|
||||
|
||||
# Config options
|
||||
SERVER_NAME = "server_name"
|
||||
CONFIG_LOCK = "server_config_in_use"
|
||||
SECRET_KEY = "macaroon_secret_key"
|
||||
|
||||
CONFIG_LOCK_DATA = """
|
||||
|
||||
## CONFIG LOCK ##
|
||||
|
||||
|
||||
# Specifies whether synapse has been started with this config.
|
||||
# If set to True the setup util will not go through the initialization
|
||||
# phase which sets the server name and server keys.
|
||||
{}: {{}}
|
||||
|
||||
|
||||
""".format(
|
||||
CONFIG_LOCK
|
||||
)
|
||||
14
synapse_topology/model/errors.py
Normal file
14
synapse_topology/model/errors.py
Normal file
@@ -0,0 +1,14 @@
|
||||
class ConfigNotFoundError(FileNotFoundError):
|
||||
def __init__(self, config_name):
|
||||
self.config_name = config_name
|
||||
|
||||
def get_config_name(self):
|
||||
return self.config_name
|
||||
|
||||
|
||||
class ServernameNotSetError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class BaseConfigInUseError(Exception):
|
||||
pass
|
||||
8
synapse_topology/model/util.py
Normal file
8
synapse_topology/model/util.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from os.path import realpath, pardir, sep, relpath
|
||||
|
||||
|
||||
def is_subpath(superpath, subpath):
|
||||
subpath = realpath(subpath)
|
||||
superpath = realpath(superpath)
|
||||
relative = relpath(subpath, superpath)
|
||||
return not relative.startswith(pardir + sep)
|
||||
3
synapse_topology/server/__init__.py
Normal file
3
synapse_topology/server/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# from .error_handlers import ErrorHandledServer as Server
|
||||
|
||||
from .error_handlers import ErrorHandledServer as Server
|
||||
0
synapse_topology/server/api.rst
Normal file
0
synapse_topology/server/api.rst
Normal file
47
synapse_topology/server/error_handlers.py
Normal file
47
synapse_topology/server/error_handlers.py
Normal file
@@ -0,0 +1,47 @@
|
||||
from jsonschema import ValidationError
|
||||
from simplejson.errors import JSONDecodeError
|
||||
from synapse_topology.model.errors import (
|
||||
BaseConfigInUseError,
|
||||
ConfigNotFoundError,
|
||||
ServernameNotSetError,
|
||||
)
|
||||
|
||||
from .server import Server
|
||||
|
||||
|
||||
class ErrorHandledServer(Server):
|
||||
app = Server.app
|
||||
|
||||
@app.handle_errors(ValidationError)
|
||||
def validation_error(self, request, failure):
|
||||
request.setResponseCode(400)
|
||||
print("Invalid post schema {}".format(failure.getErrorMessage()))
|
||||
return "Invalid post schema {}".format(failure.getErrorMessage())
|
||||
|
||||
@app.handle_errors(JSONDecodeError)
|
||||
def json_decode_error(self, request, failure):
|
||||
request.setResponseCode(400)
|
||||
return "Invalid post json"
|
||||
|
||||
@app.handle_errors(ServernameNotSetError)
|
||||
def not_initialised(self, request, failure):
|
||||
request.setResponseCode(500)
|
||||
return (
|
||||
"Config file not setup, please initialise it using the /servername endpoint"
|
||||
)
|
||||
|
||||
@app.handle_errors(ConfigNotFoundError)
|
||||
def config_not_found(self, request, failure):
|
||||
request.setResponseCode(404)
|
||||
return "The config does not exist"
|
||||
|
||||
@app.handle_errors(BaseConfigInUseError)
|
||||
def base_config_in_use(self, request, failure):
|
||||
request.setResponseCode(409)
|
||||
return "Sever name and keys already configured"
|
||||
|
||||
@app.handle_errors(Exception)
|
||||
def handle_generic_error(self, request, failure):
|
||||
print(failure)
|
||||
request.setResponseCode(500)
|
||||
return "Internal server error\n{}".format(failure)
|
||||
55
synapse_topology/server/schemas.py
Normal file
55
synapse_topology/server/schemas.py
Normal file
@@ -0,0 +1,55 @@
|
||||
BASE_CONFIG_SCHEMA = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"server_name": {"type": "string", "minlength": 1},
|
||||
"report_stats": {"type": "boolean"},
|
||||
"log_config": {"type": "string", "minlength": 1},
|
||||
"media_store_path": {"type": "string", "minlength": 1},
|
||||
"uploads_path": {"type": "string", "minlength": 1},
|
||||
"pid_file": {"type": "string", "minlength": 1},
|
||||
"listeners": {"type": "array"},
|
||||
"acme": {"type": "object"},
|
||||
"database": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string", "minlength": 1},
|
||||
"args": {"type": "object"},
|
||||
},
|
||||
"required": ["name"],
|
||||
},
|
||||
"tls_certificate_path": {"type": "string", "minlength": 1},
|
||||
"tls_private_key_path": {"type": "string", "minlength": 1},
|
||||
"server_config_in_use": {"type": "boolean"},
|
||||
},
|
||||
"required": ["server_name", "report_stats", "database"],
|
||||
}
|
||||
|
||||
CERT_PATHS_SCHEMA = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cert_path": {"type": "string", "minlength": 1},
|
||||
"cert_key_path": {"type": "string", "minlength": 1},
|
||||
},
|
||||
"required": ["cert_path", "cert_key_path"],
|
||||
}
|
||||
|
||||
CERTS_SCHEMA = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cert": {"type": "string", "minlength": 1},
|
||||
"cert_key": {"type": "string", "minlength": 1},
|
||||
},
|
||||
"required": ["cert", "cert_key"],
|
||||
}
|
||||
|
||||
PORTS_SCHEMA = {
|
||||
"type": "object",
|
||||
"properties": {"ports": {"type": "array"}},
|
||||
"required": ["ports"],
|
||||
}
|
||||
|
||||
SECRET_KEY_SCHEMA = {
|
||||
"type": "object",
|
||||
"properties": {"server_name": {"type": "string", "minlength": "1"}},
|
||||
"required": ["server_name"],
|
||||
}
|
||||
99
synapse_topology/server/server.py
Normal file
99
synapse_topology/server/server.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from os.path import abspath, dirname, join, isabs
|
||||
|
||||
from canonicaljson import json
|
||||
|
||||
from twisted.web.static import File
|
||||
|
||||
from klein import Klein
|
||||
|
||||
from .utils import port_checker
|
||||
from synapse_topology.model import constants
|
||||
from .schemas import (
|
||||
BASE_CONFIG_SCHEMA,
|
||||
CERT_PATHS_SCHEMA,
|
||||
CERTS_SCHEMA,
|
||||
PORTS_SCHEMA,
|
||||
SECRET_KEY_SCHEMA,
|
||||
)
|
||||
from .utils import validate_schema, log_body_if_fail
|
||||
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
class Server:
|
||||
app = Klein()
|
||||
|
||||
def __init__(self, model):
|
||||
self.model = model
|
||||
|
||||
def server_webui(self, request):
|
||||
client_path = abspath(join(dirname(abspath(__file__)), "../webui/dist/"))
|
||||
print(client_path)
|
||||
return File(client_path)
|
||||
|
||||
app.route("/topology_webui", branch=True)(server_webui)
|
||||
app.route("/topology_webui/", branch=True)(server_webui)
|
||||
|
||||
@app.route("/setup", methods=["GET"])
|
||||
def get_config_setup(self, request):
|
||||
return json.dumps(
|
||||
{
|
||||
constants.CONFIG_LOCK: self.model.config_in_use(),
|
||||
"config_dir": self.model.config_dir,
|
||||
}
|
||||
)
|
||||
|
||||
@app.route("/secretkey", methods=["POST"])
|
||||
@validate_schema(SECRET_KEY_SCHEMA)
|
||||
def get_secret_key(self, request, body):
|
||||
return json.dumps(
|
||||
{"secret_key": self.model.generate_secret_key(body["server_name"])}
|
||||
)
|
||||
|
||||
@app.route("/config", methods=["GET"])
|
||||
def get_config(self, request):
|
||||
return str(self.model.get_config())
|
||||
|
||||
@app.route("/config", methods=["POST"])
|
||||
@validate_schema(BASE_CONFIG_SCHEMA)
|
||||
def set_config(self, request, body):
|
||||
self.model.write_config(body)
|
||||
|
||||
@app.route("/testcertpaths", methods=["POST"])
|
||||
def test_cert_paths(self, request):
|
||||
body = json.loads(request.content.read())
|
||||
result = {}
|
||||
config_path = self.model.config_dir
|
||||
for name, path in body.items():
|
||||
if not isabs(path):
|
||||
path = abspath(join(config_path, path))
|
||||
try:
|
||||
with open(path, "r"):
|
||||
result[name] = {"invalid": False, "absolute_path": path}
|
||||
except:
|
||||
result[name] = {"invalid": True}
|
||||
return json.dumps(result)
|
||||
|
||||
@app.route("/certs", methods=["POST"])
|
||||
@validate_schema(CERTS_SCHEMA)
|
||||
def upload_certs(self, request, body):
|
||||
self.model.add_certs(**body)
|
||||
|
||||
@app.route("/ports", methods=["POST"])
|
||||
@validate_schema(PORTS_SCHEMA)
|
||||
def check_ports(self, request, body):
|
||||
results = []
|
||||
for port in body["ports"]:
|
||||
results.append(port_checker(port))
|
||||
return json.dumps({"ports": results})
|
||||
|
||||
@app.route("/start", methods=["POST"])
|
||||
def start_synapse(self, request):
|
||||
print("Starting synapse")
|
||||
subprocess.check_output(["synctl", "start", self.model.config_dir])
|
||||
|
||||
@app.route("/favicon.ico")
|
||||
def noop(self, request):
|
||||
return
|
||||
47
synapse_topology/server/utils.py
Normal file
47
synapse_topology/server/utils.py
Normal file
@@ -0,0 +1,47 @@
|
||||
from functools import wraps
|
||||
|
||||
from canonicaljson import json
|
||||
from jsonschema import validate
|
||||
|
||||
from contextlib import closing
|
||||
import socket
|
||||
|
||||
|
||||
def validate_schema(schema):
|
||||
def _wrap_validate(func):
|
||||
@wraps(func)
|
||||
def _do_validate(self, request):
|
||||
body = json.loads(request.content.read())
|
||||
print(body)
|
||||
validate(instance=body, schema=schema)
|
||||
return func(self, request, body)
|
||||
|
||||
return _do_validate
|
||||
|
||||
return _wrap_validate
|
||||
|
||||
|
||||
def port_checker(port):
|
||||
if port < 0 or 65535 < port:
|
||||
return False
|
||||
|
||||
with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
|
||||
try:
|
||||
sock.bind(("0.0.0.0", port))
|
||||
sock.listen()
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
|
||||
def log_body_if_fail(func):
|
||||
@wraps(func)
|
||||
def _log_wrapper(self, request):
|
||||
try:
|
||||
return func(self, request)
|
||||
except Exception:
|
||||
body = json.loads(request.content.read())
|
||||
print(body)
|
||||
raise
|
||||
|
||||
return _log_wrapper
|
||||
9
synapse_topology/webui/.babelrc
Normal file
9
synapse_topology/webui/.babelrc
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"presets": [
|
||||
"@babel/preset-env",
|
||||
"@babel/preset-react",
|
||||
],
|
||||
"plugins": [
|
||||
"@babel/plugin-proposal-object-rest-spread"
|
||||
],
|
||||
}
|
||||
131
synapse_topology/webui/.eslintrc.js
Normal file
131
synapse_topology/webui/.eslintrc.js
Normal file
@@ -0,0 +1,131 @@
|
||||
const path = require('path');
|
||||
|
||||
// get the path of the js-sdk so we can extend the config
|
||||
// eslint supports loading extended configs by module,
|
||||
// but only if they come from a module that starts with eslint-config-
|
||||
// So we load the filename directly (and it could be in node_modules/
|
||||
// or or ../node_modules/ etc)
|
||||
|
||||
module.exports = {
|
||||
parser: "babel-eslint",
|
||||
plugins: [
|
||||
"react",
|
||||
"babel"
|
||||
],
|
||||
env: {
|
||||
es6: true,
|
||||
},
|
||||
parserOptions: {
|
||||
ecmaFeatures: {
|
||||
jsx: true,
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
// rules we've always adhered to or now do
|
||||
"max-len": ["error", {
|
||||
code: 90,
|
||||
ignoreComments: true,
|
||||
}],
|
||||
curly: ["error", "multi-line"],
|
||||
"prefer-const": ["error"],
|
||||
"comma-dangle": ["error", {
|
||||
arrays: "always-multiline",
|
||||
objects: "always-multiline",
|
||||
imports: "always-multiline",
|
||||
exports: "always-multiline",
|
||||
functions: "always-multiline",
|
||||
}],
|
||||
|
||||
// loosen jsdoc requirements a little
|
||||
"require-jsdoc": ["error", {
|
||||
require: {
|
||||
FunctionDeclaration: false,
|
||||
}
|
||||
}],
|
||||
"valid-jsdoc": ["error", {
|
||||
requireParamDescription: false,
|
||||
requireReturn: false,
|
||||
requireReturnDescription: false,
|
||||
}],
|
||||
|
||||
// rules we do not want from eslint-recommended
|
||||
"no-console": ["off"],
|
||||
"no-constant-condition": ["off"],
|
||||
"no-empty": ["error", { "allowEmptyCatch": true }],
|
||||
|
||||
// rules we do not want from the google styleguide
|
||||
"object-curly-spacing": ["off"],
|
||||
"spaced-comment": ["off"],
|
||||
"guard-for-in": ["off"],
|
||||
|
||||
// in principle we prefer single quotes, but life is too short
|
||||
quotes: ["off"],
|
||||
|
||||
// rules we'd ideally like to adhere to, but the current
|
||||
// code does not (in most cases because it's still ES5)
|
||||
// we set these to warnings, and assert that the number
|
||||
// of warnings doesn't exceed a given threshold
|
||||
"no-var": ["warn"],
|
||||
"brace-style": ["warn", "1tbs", { "allowSingleLine": true }],
|
||||
"prefer-rest-params": ["warn"],
|
||||
"prefer-spread": ["warn"],
|
||||
"padded-blocks": ["warn"],
|
||||
"no-extend-native": ["warn"],
|
||||
"camelcase": ["warn"],
|
||||
"no-multi-spaces": ["error", { "ignoreEOLComments": true }],
|
||||
"space-before-function-paren": ["error", {
|
||||
"anonymous": "never",
|
||||
"named": "never",
|
||||
"asyncArrow": "always",
|
||||
}],
|
||||
"arrow-parens": "off",
|
||||
|
||||
// eslint's built in no-invalid-this rule breaks with class properties
|
||||
"no-invalid-this": "off",
|
||||
// so we replace it with a version that is class property aware
|
||||
"babel/no-invalid-this": "error",
|
||||
|
||||
// We appear to follow this most of the time, so let's enforce it instead
|
||||
// of occasionally following it (or catching it in review)
|
||||
"keyword-spacing": "error",
|
||||
|
||||
/** react **/
|
||||
// This just uses the react plugin to help eslint known when
|
||||
// variables have been used in JSX
|
||||
"react/jsx-uses-vars": "error",
|
||||
// Don't mark React as unused if we're using JSX
|
||||
"react/jsx-uses-react": "error",
|
||||
|
||||
// bind or arrow function in props causes performance issues
|
||||
// (but we currently use them in some places)
|
||||
// It's disabled here, but we should using it sparingly.
|
||||
"react/jsx-no-bind": "off",
|
||||
"react/jsx-key": ["error"],
|
||||
|
||||
// Components in JSX should always be defined.
|
||||
"react/jsx-no-undef": "error",
|
||||
|
||||
// Assert no spacing in JSX curly brackets
|
||||
// <Element prop={ consideredError} prop={notConsideredError} />
|
||||
//
|
||||
// https://github.com/yannickcr/eslint-plugin-react/blob/HEAD/docs/rules/jsx-curly-spacing.md
|
||||
//
|
||||
// Disabled for now - if anything we'd like to *enforce* spacing in JSX
|
||||
// curly brackets for legibility, but in practice it's not clear that the
|
||||
// consistency particularly improves legibility here. --Matthew
|
||||
//
|
||||
// "react/jsx-curly-spacing": ["error", {"when": "never", "children": {"when": "always"}}],
|
||||
|
||||
// Assert spacing before self-closing JSX tags, and no spacing before or
|
||||
// after the closing slash, and no spacing after the opening bracket of
|
||||
// the opening tag or closing tag.
|
||||
//
|
||||
// https://github.com/yannickcr/eslint-plugin-react/blob/HEAD/docs/rules/jsx-tag-spacing.md
|
||||
"react/jsx-tag-spacing": ["error"],
|
||||
},
|
||||
settings: {
|
||||
flowtype: {
|
||||
onlyFilesWithFlowAnnotation: true
|
||||
},
|
||||
},
|
||||
};
|
||||
3
synapse_topology/webui/.gitignore
vendored
Normal file
3
synapse_topology/webui/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules
|
||||
yarn-error.log
|
||||
dist
|
||||
23
synapse_topology/webui/.stylelintrc.js
Normal file
23
synapse_topology/webui/.stylelintrc.js
Normal file
@@ -0,0 +1,23 @@
|
||||
module.exports = {
|
||||
"extends": "stylelint-config-standard",
|
||||
"plugins": [
|
||||
"stylelint-scss",
|
||||
],
|
||||
"rules": {
|
||||
"indentation": 4,
|
||||
"comment-empty-line-before": null,
|
||||
"declaration-empty-line-before": null,
|
||||
"length-zero-no-unit": null,
|
||||
"rule-empty-line-before": null,
|
||||
"color-hex-length": null,
|
||||
"max-empty-lines": null,
|
||||
"number-no-trailing-zeros": null,
|
||||
"number-leading-zero": null,
|
||||
"selector-list-comma-newline-after": null,
|
||||
"at-rule-no-unknown": null,
|
||||
"scss/at-rule-no-unknown": [true, {
|
||||
// https://github.com/vector-im/riot-web/issues/10544
|
||||
"ignoreAtRules": ["define-mixin"],
|
||||
}],
|
||||
}
|
||||
}
|
||||
1130
synapse_topology/webui/code_style.md
Normal file
1130
synapse_topology/webui/code_style.md
Normal file
File diff suppressed because it is too large
Load Diff
52
synapse_topology/webui/package.json
Normal file
52
synapse_topology/webui/package.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "synapse_topology_webui",
|
||||
"version": "0.0.0",
|
||||
"description": "A simple webui for initialising the synapse startup",
|
||||
"main": "index.js",
|
||||
"author": "Jorik Schellekens (matrix.org)",
|
||||
"license": "Apache-2.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.5.5",
|
||||
"@babel/core": "^7.5.5",
|
||||
"@babel/node": "^7.5.5",
|
||||
"@babel/plugin-proposal-object-rest-spread": "^7.5.5",
|
||||
"@babel/preset-env": "^7.5.5",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@babel/register": "^7.5.5",
|
||||
"babel-eslint": "^10.0.2",
|
||||
"babel-loader": "^8.0.6",
|
||||
"css-loader": "^3.2.0",
|
||||
"eslint": "^6.1.0",
|
||||
"eslint-plugin-babel": "^5.3.0",
|
||||
"eslint-plugin-react": "^7.14.3",
|
||||
"file-loader": "^4.1.0",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"html-webpack-tags-plugin": "^2.0.13",
|
||||
"less": "^3.9.0",
|
||||
"node-sass": "^4.12.0",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"redux-devtools-extension": "^2.13.8",
|
||||
"sass-loader": "^7.2.0",
|
||||
"style-loader": "^0.23.1",
|
||||
"webpack": "^4.38.0",
|
||||
"webpack-cli": "^3.3.6",
|
||||
"webpack-dev-server": "^3.7.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack -p --progress --config webpack.config.babel.js",
|
||||
"dev-build": "webpack --progress -d --config webpack.config.babel.js",
|
||||
"watch": "webpack --progress -d --config webpack.config.babel.js --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"fetch-absolute": "^1.0.0",
|
||||
"react-bootstrap": "^1.0.0-beta.11",
|
||||
"react-icons": "^3.7.0",
|
||||
"react-localize-redux": "^3.5.3",
|
||||
"react-redux": "^7.1.0",
|
||||
"redux": "^4.0.4",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"yaml": "^1.6.0"
|
||||
}
|
||||
}
|
||||
BIN
synapse_topology/webui/src/fonts/LiberationSans-Bold.ttf
Normal file
BIN
synapse_topology/webui/src/fonts/LiberationSans-Bold.ttf
Normal file
Binary file not shown.
BIN
synapse_topology/webui/src/fonts/LiberationSans-BoldItalic.ttf
Normal file
BIN
synapse_topology/webui/src/fonts/LiberationSans-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
synapse_topology/webui/src/fonts/LiberationSans-Italic.ttf
Normal file
BIN
synapse_topology/webui/src/fonts/LiberationSans-Italic.ttf
Normal file
Binary file not shown.
BIN
synapse_topology/webui/src/fonts/LiberationSans-Regular.ttf
Normal file
BIN
synapse_topology/webui/src/fonts/LiberationSans-Regular.ttf
Normal file
Binary file not shown.
46
synapse_topology/webui/src/fonts/SIL Open Font License.txt
Normal file
46
synapse_topology/webui/src/fonts/SIL Open Font License.txt
Normal file
@@ -0,0 +1,46 @@
|
||||
Digitized data copyright (c) 2010 Google Corporation
|
||||
with Reserved Font Arimo, Tinos and Cousine.
|
||||
Copyright (c) 2012 Red Hat, Inc.
|
||||
with Reserved Font Name Liberation.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
5
synapse_topology/webui/src/fonts/matrix-logo.svg
Normal file
5
synapse_topology/webui/src/fonts/matrix-logo.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg width="75" height="32" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="#2D2D2D" fillRule="nonzero">
|
||||
<path d="M.936.732V31.25H3.13v.732H.095V0h3.034v.732zM9.386 10.407v1.544h.044a4.461 4.461 0 0 1 1.487-1.368c.58-.323 1.245-.485 1.993-.485.72 0 1.377.14 1.972.42.595.279 1.047.771 1.355 1.477.338-.5.796-.941 1.377-1.323.58-.383 1.266-.574 2.06-.574.602 0 1.16.074 1.674.22.514.148.954.383 1.322.707.366.323.653.746.859 1.268.205.522.308 1.15.308 1.887v7.633H20.71v-6.464c0-.383-.015-.743-.044-1.082a2.305 2.305 0 0 0-.242-.882 1.473 1.473 0 0 0-.584-.596c-.257-.146-.606-.22-1.047-.22-.44 0-.796.085-1.068.253-.272.17-.485.39-.639.662a2.654 2.654 0 0 0-.308.927 7.074 7.074 0 0 0-.078 1.048v6.354h-3.128v-6.398c0-.338-.007-.673-.021-1.004a2.825 2.825 0 0 0-.188-.916 1.411 1.411 0 0 0-.55-.673c-.258-.168-.636-.253-1.135-.253a2.33 2.33 0 0 0-.584.1 1.94 1.94 0 0 0-.705.374c-.228.184-.422.449-.584.794-.161.346-.242.798-.242 1.357v6.619H6.434V10.407h2.952zM25.842 12.084a3.751 3.751 0 0 1 1.233-1.17 5.37 5.37 0 0 1 1.685-.629 9.579 9.579 0 0 1 1.884-.187c.573 0 1.153.04 1.74.121.588.081 1.124.24 1.609.475.484.235.88.562 1.19.981.308.42.462.975.462 1.666v5.934c0 .516.03 1.008.088 1.478.058.471.161.824.308 1.06H32.87a4.435 4.435 0 0 1-.22-1.104c-.5.515-1.087.876-1.762 1.081a7.084 7.084 0 0 1-2.071.31c-.544 0-1.05-.067-1.52-.2a3.472 3.472 0 0 1-1.234-.617 2.87 2.87 0 0 1-.826-1.059c-.199-.426-.298-.934-.298-1.522 0-.647.114-1.18.342-1.6.227-.419.52-.753.881-1.004.36-.25.771-.437 1.234-.562.462-.125.929-.224 1.399-.298.47-.073.932-.132 1.387-.176.456-.044.86-.11 1.212-.199.353-.088.631-.217.837-.386.206-.169.301-.415.287-.74 0-.337-.055-.606-.166-.804a1.217 1.217 0 0 0-.44-.464 1.737 1.737 0 0 0-.639-.22 5.292 5.292 0 0 0-.782-.055c-.617 0-1.101.132-1.454.397-.352.264-.558.706-.617 1.323h-3.128c.044-.735.227-1.345.55-1.83zm6.179 4.423a5.095 5.095 0 0 1-.639.165 9.68 9.68 0 0 1-.716.11c-.25.03-.5.067-.749.11a5.616 5.616 0 0 0-.694.177 2.057 2.057 0 0 0-.594.298c-.17.125-.305.284-.408.474-.103.192-.154.434-.154.728 0 .28.051.515.154.706.103.192.242.342.419.453.176.11.381.187.617.231.234.044.477.066.726.066.617 0 1.094-.102 1.432-.309.338-.205.587-.452.75-.739.16-.286.26-.576.297-.87.036-.295.055-.53.055-.707v-1.17a1.4 1.4 0 0 1-.496.277zM43.884 10.407v2.096h-2.291v5.647c0 .53.088.883.264 1.059.176.177.529.265 1.057.265.177 0 .345-.007.507-.022.161-.015.316-.037.463-.066v2.426a7.49 7.49 0 0 1-.882.089 21.67 21.67 0 0 1-.947.022c-.484 0-.944-.034-1.377-.1a3.233 3.233 0 0 1-1.145-.386 2.04 2.04 0 0 1-.782-.816c-.191-.353-.287-.816-.287-1.39v-6.728H36.57v-2.096h1.894v-3.42h3.129v3.42h2.29zM48.355 10.407v2.118h.044a3.907 3.907 0 0 1 1.454-1.754 4.213 4.213 0 0 1 1.036-.497 3.734 3.734 0 0 1 1.145-.176c.206 0 .433.037.683.11v2.912a5.862 5.862 0 0 0-.528-.077 5.566 5.566 0 0 0-.595-.033c-.573 0-1.058.096-1.454.287a2.52 2.52 0 0 0-.958.783 3.143 3.143 0 0 0-.518 1.158 6.32 6.32 0 0 0-.154 1.434v5.14h-3.128V10.407h2.973zM54.039 8.642V6.06h3.128v2.582H54.04zm3.128 1.765v11.405H54.04V10.407h3.128zM58.797 10.407h3.569l2.005 2.978 1.982-2.978h3.459l-3.745 5.339 4.208 6.067h-3.57l-2.378-3.596-2.38 3.596h-3.502l4.097-6.001zM74.094 31.25V.732H71.9V0h3.035v31.982H71.9v-.732z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
24
synapse_topology/webui/src/js/actions/constants.js
Normal file
24
synapse_topology/webui/src/js/actions/constants.js
Normal file
@@ -0,0 +1,24 @@
|
||||
export const DELEGATION_TYPES = {
|
||||
LOCAL: "local",
|
||||
WELL_KNOWN: ".well_known",
|
||||
DNS: "DNS SRV",
|
||||
};
|
||||
|
||||
export const REVERSE_PROXY_TYPES = {
|
||||
CADDY: "CADDY",
|
||||
APACHE: "APACHE",
|
||||
HAPROXY: "HAPROXY",
|
||||
NGINX: "NGINX",
|
||||
OTHER: "OTHER",
|
||||
};
|
||||
|
||||
export const TLS_TYPES = {
|
||||
ACME: "ACME",
|
||||
TLS: "TLS",
|
||||
REVERSE_PROXY: "REVERSE_PROXY",
|
||||
};
|
||||
|
||||
export const DATABASE_TYPES = {
|
||||
SQLITE3: "sqlite3",
|
||||
POSTGRES: "psycopg2",
|
||||
};
|
||||
329
synapse_topology/webui/src/js/actions/index.js
Normal file
329
synapse_topology/webui/src/js/actions/index.js
Normal file
@@ -0,0 +1,329 @@
|
||||
import {
|
||||
ADVANCE_UI,
|
||||
BACK_UI,
|
||||
SET_SERVERNAME,
|
||||
SET_STATS,
|
||||
BASE_CONFIG_CHECKED,
|
||||
FAIL,
|
||||
SET_SECRET_KEY,
|
||||
GETTING_SECRET_KEY,
|
||||
SET_DELEGATION,
|
||||
SET_DELEGATION_SERVERNAME,
|
||||
SET_DELEGATION_PORTS,
|
||||
SET_REVERSE_PROXY,
|
||||
SET_TLS,
|
||||
TESTING_TLS_CERT_PATHS,
|
||||
SET_TLS_CERT_PATHS,
|
||||
SET_TLS_CERT_PATHS_VALIDITY,
|
||||
SET_TLS_CERT_FILES,
|
||||
UPLOADING_TLS_CERT_PATHS,
|
||||
TESTING_SYNAPSE_PORTS,
|
||||
SET_SYNAPSE_PORTS,
|
||||
SET_SYNAPSE_PORTS_FREE,
|
||||
SET_DATABASE,
|
||||
SET_CONFIG_DIR,
|
||||
SYNAPSE_START_FAILED,
|
||||
} from './types';
|
||||
|
||||
import {
|
||||
getServerSetup,
|
||||
getSecretkey,
|
||||
postCertPaths,
|
||||
postCerts,
|
||||
testPorts,
|
||||
postConfig,
|
||||
startSynapse,
|
||||
} from '../api';
|
||||
|
||||
import { CONFIG_LOCK, CONFIG_DIR } from '../api/constants';
|
||||
import { baseConfigToSynapseConfig } from '../utils/yaml';
|
||||
|
||||
export const startup = () => {
|
||||
|
||||
return dispatch => {
|
||||
|
||||
getServerSetup().then(
|
||||
result => {
|
||||
|
||||
dispatch(start(result[CONFIG_LOCK]));
|
||||
dispatch(setConfigDir(result[CONFIG_DIR]));
|
||||
|
||||
},
|
||||
error => dispatch(fail(error)),
|
||||
)
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
const setConfigDir = dir => ({
|
||||
type: SET_CONFIG_DIR,
|
||||
configDir: dir,
|
||||
});
|
||||
|
||||
export const generateSecretKeys = serverName => {
|
||||
|
||||
return dispatch => {
|
||||
dispatch(getSecretKey(serverName))
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
export const setTlsCertPaths = (certPath, certKeyPath, callback) => {
|
||||
|
||||
return dispatch => {
|
||||
|
||||
dispatch(testingTlsCertPaths(true));
|
||||
postCertPaths(certPath, certKeyPath)
|
||||
.then(
|
||||
result => dispatch(checkTlsCertPathValidity(result, callback)),
|
||||
error => dispatch(fail(error)),
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
const setTlsCerts = (certPath, certKeyPath) => ({
|
||||
type: SET_TLS_CERT_PATHS,
|
||||
certPath: certPath,
|
||||
certKeyPath: certKeyPath,
|
||||
});
|
||||
|
||||
const testingTlsCertPaths = testing => ({
|
||||
type: TESTING_TLS_CERT_PATHS,
|
||||
testing,
|
||||
});
|
||||
|
||||
const checkTlsCertPathValidity =
|
||||
({ cert_path: certPath, cert_key_path: certKeyPath }, callback) => {
|
||||
|
||||
return dispatch => {
|
||||
|
||||
dispatch(testingTlsCertPaths(false));
|
||||
dispatch(setTlsCerts(certPath.absolute_path, certKeyPath.absolute_path))
|
||||
dispatch(setCertPathValidity({ certPath, certKeyPath }));
|
||||
|
||||
if (!certPath.invalid && !certKeyPath.invalid) {
|
||||
|
||||
dispatch(advanceUI());
|
||||
callback();
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
export const uploadTlsCertFiles = (tlsCertFile, tlsCertKeyFile) =>
|
||||
|
||||
dispatch => {
|
||||
|
||||
dispatch(setTlsCertFiles(tlsCertFile, tlsCertKeyFile));
|
||||
dispatch(uploadingTlsCertFiles(true));
|
||||
postCerts(tlsCertFile, tlsCertKeyFile)
|
||||
.then(
|
||||
result => {
|
||||
|
||||
dispatch(uploadingTlsCertFiles(false));
|
||||
dispatch(advanceUI())
|
||||
|
||||
},
|
||||
error => dispatch(fail(error)),
|
||||
)
|
||||
|
||||
};
|
||||
|
||||
const uploadingTlsCertFiles = uploading => ({
|
||||
type: UPLOADING_TLS_CERT_PATHS,
|
||||
uploading,
|
||||
});
|
||||
|
||||
export const setTlsCertFiles = (tlsCertFile, tlsCertKeyFile) => ({
|
||||
type: SET_TLS_CERT_FILES,
|
||||
tlsCertFile,
|
||||
tlsCertKeyFile,
|
||||
})
|
||||
|
||||
const setCertPathValidity = ({ certPath, certKeyPath }) => ({
|
||||
type: SET_TLS_CERT_PATHS_VALIDITY,
|
||||
certPathInvalid: certPath.invalid,
|
||||
certKeyPathInvalid: certKeyPath.invalid,
|
||||
});
|
||||
|
||||
export const gettingSecretKeys = () => ({
|
||||
type: GETTING_SECRET_KEY,
|
||||
});
|
||||
|
||||
export const getSecretKey = serverName => {
|
||||
|
||||
return dispatch => {
|
||||
|
||||
getSecretkey(serverName).then(
|
||||
result => dispatch(setSecretKey(result)),
|
||||
error => dispatch(fail(error)),
|
||||
)
|
||||
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
export const setSecretKey = key => ({
|
||||
type: SET_SECRET_KEY,
|
||||
key,
|
||||
});
|
||||
|
||||
export const start = setupDone => ({
|
||||
type: BASE_CONFIG_CHECKED,
|
||||
setupDone,
|
||||
});
|
||||
|
||||
export const fail = reason => ({
|
||||
type: FAIL,
|
||||
reason,
|
||||
});
|
||||
|
||||
export const advanceUI = option => ({
|
||||
type: ADVANCE_UI,
|
||||
option,
|
||||
});
|
||||
|
||||
export const setServername = servername => ({
|
||||
type: SET_SERVERNAME,
|
||||
servername,
|
||||
});
|
||||
|
||||
export const setStats = consent => ({
|
||||
type: SET_STATS,
|
||||
consent,
|
||||
});
|
||||
|
||||
export const setDelegation = delegationType => ({
|
||||
type: SET_DELEGATION,
|
||||
delegationType,
|
||||
});
|
||||
|
||||
export const setDelegationServername = servername => ({
|
||||
type: SET_DELEGATION_SERVERNAME,
|
||||
servername,
|
||||
});
|
||||
|
||||
export const setDelegationPorts = (federationPort, clientPort) => ({
|
||||
type: SET_DELEGATION_PORTS,
|
||||
federationPort,
|
||||
clientPort,
|
||||
});
|
||||
|
||||
export const setReverseProxy = proxyType => ({
|
||||
type: SET_REVERSE_PROXY,
|
||||
proxyType,
|
||||
});
|
||||
|
||||
export const setTls = tlsType => ({
|
||||
type: SET_TLS,
|
||||
tlsType,
|
||||
});
|
||||
|
||||
export const setSynapsePorts = (federationPort, clientPort, callback) => {
|
||||
|
||||
const fedPortPriv = federationPort < 1024;
|
||||
const clientPortPriv = clientPort < 1024;
|
||||
|
||||
return dispatch => {
|
||||
|
||||
dispatch(testingSynapsePorts(true));
|
||||
dispatch({
|
||||
type: SET_SYNAPSE_PORTS,
|
||||
federationPort,
|
||||
clientPort,
|
||||
})
|
||||
testPorts([federationPort, clientPort])
|
||||
.then(
|
||||
results => dispatch(updatePortsFree(
|
||||
fedPortPriv ? true : results.ports[0],
|
||||
clientPortPriv ? true : results.ports[1],
|
||||
callback,
|
||||
)),
|
||||
error => dispatch(fail(error)),
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export const updatePortsFree =
|
||||
(synapseFederationPortFree, synapseClientPortFree, callback) => {
|
||||
|
||||
return dispatch => {
|
||||
|
||||
dispatch(testingSynapsePorts(false));
|
||||
dispatch({
|
||||
type: SET_SYNAPSE_PORTS_FREE,
|
||||
synapseFederationPortFree,
|
||||
synapseClientPortFree,
|
||||
});
|
||||
if (synapseFederationPortFree && synapseClientPortFree) {
|
||||
|
||||
callback();
|
||||
dispatch(advanceUI());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const testingSynapsePorts = verifying => ({
|
||||
type: TESTING_SYNAPSE_PORTS,
|
||||
verifying,
|
||||
})
|
||||
|
||||
export const setDatabase = databaseConfig => ({
|
||||
type: SET_DATABASE,
|
||||
databaseConfig,
|
||||
})
|
||||
|
||||
export const writeConfig = (callback) => {
|
||||
|
||||
return (dispatch, getState) => {
|
||||
|
||||
postConfig(baseConfigToSynapseConfig(getState().baseConfig))
|
||||
.then(
|
||||
res => startSynapse().then(
|
||||
res => {
|
||||
if (res.ok) {
|
||||
|
||||
dispatch(advanceUI());
|
||||
callback();
|
||||
|
||||
} else {
|
||||
dispatch(synapseStartFailed());
|
||||
}
|
||||
},
|
||||
error => {
|
||||
|
||||
fail(error);
|
||||
dispatch(synapseStartFailed());
|
||||
|
||||
}
|
||||
),
|
||||
error => {
|
||||
|
||||
dispatch(fail(error));
|
||||
dispatch(synapseStartStartFailed())
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const synapseStartFailed = () => ({
|
||||
type: SYNAPSE_START_FAILED,
|
||||
})
|
||||
|
||||
export const resetUI = (ui) => ({
|
||||
type: BACK_UI,
|
||||
ui,
|
||||
})
|
||||
25
synapse_topology/webui/src/js/actions/types.js
Normal file
25
synapse_topology/webui/src/js/actions/types.js
Normal file
@@ -0,0 +1,25 @@
|
||||
export const ADVANCE_UI = 'ADVANCE_UI';
|
||||
export const BACK_UI = 'BACK_UI';
|
||||
export const SET_SERVERNAME = 'SET_SERVERNAME';
|
||||
export const SET_STATS = 'SET_STATS';
|
||||
export const BASE_CONFIG_CHECKED = 'BASE_CONFIG_CHECKED';
|
||||
export const FAIL = 'NETWORK_FAIL';
|
||||
export const SET_SECRET_KEY = 'SET_SECRET_KEY';
|
||||
export const GETTING_SECRET_KEY = 'GETTING_SECRET_KEY';
|
||||
export const SET_DELEGATION = 'SET_DELEGATION';
|
||||
export const SET_DELEGATION_SERVERNAME = 'SET_DELEGATION_SERVERNAME';
|
||||
export const SET_DELEGATION_PORTS = 'SET_DELEGATION_PORTS';
|
||||
export const SET_REVERSE_PROXY = 'SET_REVERSE_PROXY';
|
||||
export const TESTING_TLS_CERT_PATHS = 'TESTING_TLS_CERT_PATHS';
|
||||
export const UPLOADING_TLS_CERT_PATHS = 'UPLOADING_TLS_CERT_PATHS';
|
||||
export const SET_TLS = 'SET_TLS';
|
||||
export const SET_TLS_CERT_PATHS = 'SET_TLS_CERT_PATHS';
|
||||
export const SET_TLS_CERT_PATHS_VALIDITY = 'SET_TLS_CERT_PATHS_VALIDITY';
|
||||
export const SET_TLS_CERT_FILES = 'SET_TLS_CERT_FILES';
|
||||
export const TESTING_SYNAPSE_PORTS = 'TESTING_SYNAPSE_PORTS';
|
||||
export const SET_SYNAPSE_PORTS = 'SET_SYNAPSE_PORTS';
|
||||
export const SET_SYNAPSE_PORTS_FREE = 'SET_SYNAPSE_PORTS_IN_USE';
|
||||
export const SET_DATABASE = 'SET_DATABASE';
|
||||
export const SET_CONFIG_DIR = 'SET_CONFIG_DIR';
|
||||
export const WRITE_CONFIG = 'WRITE_CONFIG';
|
||||
export const SYNAPSE_START_FAILED = 'SYNAPSE_START_FAILED';
|
||||
11
synapse_topology/webui/src/js/api/constants.js
Normal file
11
synapse_topology/webui/src/js/api/constants.js
Normal file
@@ -0,0 +1,11 @@
|
||||
export const API_URL = "http://localhost:8888/";
|
||||
export const SERVER_NAME = "/servername";
|
||||
export const SECRET_KEY = "/secretkey";
|
||||
export const CONFIG = "/config";
|
||||
export const CONFIG_SOMETHING = "/config_something";
|
||||
export const SETUP_CHECK = "/setup";
|
||||
export const CERT_PATHS = "/testcertpaths";
|
||||
export const TEST_PORTS = "/ports";
|
||||
export const CONFIG_LOCK = "server_config_in_use";
|
||||
export const CONFIG_DIR = "config_dir";
|
||||
export const START = "/start";
|
||||
91
synapse_topology/webui/src/js/api/index.js
Normal file
91
synapse_topology/webui/src/js/api/index.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import fetchAbsolute from 'fetch-absolute';
|
||||
import {
|
||||
API_URL,
|
||||
CONFIG,
|
||||
SECRET_KEY,
|
||||
SERVER_NAME,
|
||||
SETUP_CHECK,
|
||||
CERT_PATHS,
|
||||
TEST_PORTS,
|
||||
START,
|
||||
} from './constants';
|
||||
|
||||
const fetchAbs = fetchAbsolute(fetch)(API_URL)
|
||||
|
||||
export const getServerName = () =>
|
||||
fetchAbs(SERVER_NAME)
|
||||
.then(res => res.json())
|
||||
|
||||
|
||||
export const postCertPaths = (certPath, certKeyPath) =>
|
||||
fetchAbs(
|
||||
CERT_PATHS,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
// eslint-disable-next-line camelcase
|
||||
cert_path: certPath,
|
||||
// eslint-disable-next-line camelcase
|
||||
cert_key_path: certKeyPath,
|
||||
}),
|
||||
},
|
||||
).then(res => res.json())
|
||||
|
||||
export const postCerts = (cert, certKey) =>
|
||||
fetchAbs(
|
||||
CERT_PATHS,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
cert,
|
||||
// eslint-disable-next-line camelcase
|
||||
cert_key: certKey,
|
||||
}),
|
||||
},
|
||||
)
|
||||
|
||||
export const testPorts = (ports) =>
|
||||
fetchAbs(
|
||||
TEST_PORTS,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
ports,
|
||||
}),
|
||||
},
|
||||
).then(res => res.json())
|
||||
|
||||
export const getSecretkey = serverName =>
|
||||
fetchAbs(
|
||||
SECRET_KEY,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
server_name: serverName,
|
||||
})
|
||||
}
|
||||
)
|
||||
.then(res => res.json())
|
||||
.then(json => json.secret_key)
|
||||
|
||||
|
||||
export const postConfig = (config) =>
|
||||
fetchAbs(
|
||||
CONFIG,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify(config),
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
// Checks if the server's base config has been setup.
|
||||
export const getServerSetup = () => fetchAbs(SETUP_CHECK)
|
||||
.then(res => res.json())
|
||||
|
||||
export const startSynapse = () => fetchAbs(
|
||||
START,
|
||||
{
|
||||
method: 'POST',
|
||||
}
|
||||
)
|
||||
24
synapse_topology/webui/src/js/components/AccordionToggle.jsx
Normal file
24
synapse_topology/webui/src/js/components/AccordionToggle.jsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
import useAccordionToggle from 'react-bootstrap/useAccordionToggle';
|
||||
import { reset } from 'ansi-colors';
|
||||
import Chevron from './Chevron';
|
||||
|
||||
export default ({ active, open, children, eventKey, as, reset }) => {
|
||||
const clickable = active & !open;
|
||||
const toggle = useAccordionToggle(eventKey);
|
||||
const decoratedOnClick = () => {
|
||||
|
||||
if (clickable) {
|
||||
|
||||
toggle();
|
||||
reset();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
const As = as;
|
||||
return <div className={clickable ? "active-card-header" : "inactive-card-header"}>
|
||||
<As onClick={decoratedOnClick}> {children} <Chevron open={open} /></As>
|
||||
</div>
|
||||
|
||||
}
|
||||
39
synapse_topology/webui/src/js/components/BaseIntro.jsx
Normal file
39
synapse_topology/webui/src/js/components/BaseIntro.jsx
Normal file
@@ -0,0 +1,39 @@
|
||||
/* eslint-disable max-len */
|
||||
import React from 'react';
|
||||
|
||||
import ContentWrapper from '../containers/ContentWrapper';
|
||||
import ButtonDisplay from './ButtonDisplay';
|
||||
|
||||
import useAccordionToggle from 'react-bootstrap/useAccordionToggle';
|
||||
import { nextUI } from '../reducers/setup-ui-reducer';
|
||||
|
||||
export default ({ started, servername, onClick }) => {
|
||||
|
||||
const toggle = useAccordionToggle(nextUI())
|
||||
const wrappedOnClick = () => {
|
||||
|
||||
onClick();
|
||||
toggle();
|
||||
|
||||
}
|
||||
|
||||
const prompt = servername ? "Configuring " + servername : "Let's configure your Synapse server."
|
||||
|
||||
return <ContentWrapper>
|
||||
<div className='baseintro'>
|
||||
<svg width="113" height="48" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="#2D2D2D" fillRule="nonzero">
|
||||
<path d="M1.404 1.098v45.776h3.29v1.099H.142V0h4.552v1.098zM14.079 15.61v2.317h.065c.617-.882 1.36-1.567 2.231-2.052.87-.485 1.867-.728 2.99-.728 1.08 0 2.066.21 2.958.629.892.42 1.57 1.158 2.032 2.217.507-.75 1.195-1.412 2.066-1.986.87-.573 1.9-.86 3.09-.86.903 0 1.74.11 2.511.33.77.222 1.432.575 1.982 1.06.55.485.98 1.12 1.29 1.902.307.784.462 1.727.462 2.83v11.45h-4.693v-9.696c0-.574-.022-1.114-.066-1.622-.044-.507-.165-.948-.363-1.323a2.21 2.21 0 0 0-.876-.894c-.385-.22-.909-.33-1.57-.33-.66 0-1.195.127-1.602.38a2.758 2.758 0 0 0-.958.993 3.981 3.981 0 0 0-.463 1.39 10.611 10.611 0 0 0-.116 1.572v9.53h-4.692v-9.597c0-.507-.011-1.009-.033-1.505a4.238 4.238 0 0 0-.28-1.374 2.117 2.117 0 0 0-.827-1.01c-.386-.252-.953-.38-1.702-.38-.22 0-.512.05-.875.15-.364.099-.717.287-1.058.562-.342.276-.633.673-.876 1.191-.242.519-.363 1.197-.363 2.035v9.928H9.65V15.61h4.428zM38.763 18.125a5.627 5.627 0 0 1 1.85-1.754 8.056 8.056 0 0 1 2.528-.943 14.368 14.368 0 0 1 2.825-.281c.86 0 1.73.06 2.61.182.881.121 1.686.359 2.413.711a4.757 4.757 0 0 1 1.784 1.473c.463.628.694 1.461.694 2.498v8.902c0 .773.044 1.511.132 2.217.088.706.242 1.236.463 1.588h-4.758a6.888 6.888 0 0 1-.33-1.655 6.117 6.117 0 0 1-2.644 1.623 10.625 10.625 0 0 1-3.107.463c-.815 0-1.575-.1-2.28-.298a5.207 5.207 0 0 1-1.85-.927 4.304 4.304 0 0 1-1.24-1.588c-.297-.64-.446-1.401-.446-2.283 0-.97.17-1.77.513-2.4a4.28 4.28 0 0 1 1.322-1.505 5.913 5.913 0 0 1 1.85-.844 19.932 19.932 0 0 1 2.098-.447c.705-.11 1.4-.198 2.082-.264a12.534 12.534 0 0 0 1.818-.298c.529-.133.947-.325 1.255-.58.308-.253.452-.622.43-1.108 0-.507-.083-.91-.248-1.208a1.825 1.825 0 0 0-.66-.695 2.606 2.606 0 0 0-.959-.331 7.938 7.938 0 0 0-1.173-.083c-.925 0-1.652.199-2.18.596-.53.397-.838 1.06-.926 1.986h-4.692c.065-1.103.34-2.02.826-2.747zm9.268 6.635c-.297.1-.617.182-.958.248-.341.067-.7.122-1.074.166-.374.044-.749.1-1.123.165-.353.066-.7.155-1.04.265-.343.11-.64.26-.893.447a2.125 2.125 0 0 0-.612.711c-.154.287-.231.651-.231 1.092 0 .419.077.773.231 1.059.154.287.364.513.628.678.265.166.573.282.926.348.352.066.715.099 1.09.099.925 0 1.64-.154 2.148-.463.506-.309.88-.679 1.123-1.11.242-.43.391-.864.447-1.306.054-.44.082-.794.082-1.059v-1.754a2.101 2.101 0 0 1-.744.414zM65.825 15.61v3.144H62.39v8.472c0 .793.132 1.323.397 1.588.263.264.793.397 1.586.397.264 0 .517-.011.76-.033a6.52 6.52 0 0 0 .693-.1v3.64c-.396.067-.837.11-1.321.133-.485.021-.959.033-1.421.033-.727 0-1.416-.05-2.065-.15a4.85 4.85 0 0 1-1.719-.578 3.06 3.06 0 0 1-1.173-1.224c-.286-.53-.43-1.225-.43-2.086V18.754h-2.841V15.61h2.842v-5.13h4.692v5.13h3.436zM72.533 15.61v3.177h.066c.22-.53.517-1.02.892-1.473a5.86 5.86 0 0 1 1.289-1.158 6.32 6.32 0 0 1 1.553-.745 5.601 5.601 0 0 1 1.719-.265c.308 0 .649.056 1.024.166v4.369a8.793 8.793 0 0 0-.793-.116 8.35 8.35 0 0 0-.893-.05c-.859 0-1.586.144-2.18.43a3.779 3.779 0 0 0-1.438 1.175 4.714 4.714 0 0 0-.776 1.737 9.48 9.48 0 0 0-.232 2.151v7.71h-4.692V15.61h4.461zM81.058 12.962V9.091h4.693v3.871h-4.693zm4.693 2.648v17.109h-4.693V15.61h4.693zM88.196 15.61h5.353l3.007 4.467 2.974-4.467h5.188L99.1 23.618l6.311 9.1h-5.353l-3.57-5.393-3.568 5.394h-5.254l6.146-9.001zM111.14 46.874V1.098h-3.289V0h4.552v47.973h-4.552v-1.099z" />
|
||||
</g>
|
||||
</svg>
|
||||
<h1>Setting up Synapse</h1>
|
||||
<p>{prompt}</p>
|
||||
{
|
||||
!started ?
|
||||
<ButtonDisplay><button onClick={wrappedOnClick}>Get Started</button></ButtonDisplay>
|
||||
: undefined
|
||||
}
|
||||
</div>
|
||||
</ContentWrapper>
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
import style from '../../scss/main.scss';
|
||||
|
||||
export default ({ children }) => <div className={style.buttonDisplay}>{children}</div>
|
||||
7
synapse_topology/webui/src/js/components/Chevron.jsx
Normal file
7
synapse_topology/webui/src/js/components/Chevron.jsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
import { FaChevronRight, FaChevronDown } from 'react-icons/fa'
|
||||
|
||||
export default ({ open }) =>
|
||||
<span className="chevron">
|
||||
{open ? <FaChevronDown /> : <FaChevronRight />}
|
||||
</span>
|
||||
94
synapse_topology/webui/src/js/components/CompleteSetup.jsx
Normal file
94
synapse_topology/webui/src/js/components/CompleteSetup.jsx
Normal file
@@ -0,0 +1,94 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import Accordion from 'react-bootstrap/Accordion';
|
||||
import Card from 'react-bootstrap/Card';
|
||||
import useAccordionToggle from 'react-bootstrap/useAccordionToggle';
|
||||
|
||||
import ReverseProxySampleConfig from '../containers/ReverseProxySampleConfig'
|
||||
import DelegationSampleConfig from '../containers/DelegationSampleConfig';
|
||||
import AccordionToggle from '../containers/AccordionToggle';
|
||||
import InlineError from '../components/InlineError';
|
||||
|
||||
import { TLS_TYPES, DELEGATION_TYPES } from '../actions/constants';
|
||||
import { COMPLETE_UI } from '../reducers/ui-constants';
|
||||
import { nextUI } from '../reducers/setup-ui-reducer';
|
||||
|
||||
export default ({
|
||||
tlsType,
|
||||
delegationType,
|
||||
synapseStartFailed,
|
||||
configDir,
|
||||
onClick,
|
||||
}) => {
|
||||
const toggle = useAccordionToggle(nextUI(COMPLETE_UI));
|
||||
|
||||
const decoratedOnClick = () => {
|
||||
onClick(toggle);
|
||||
}
|
||||
|
||||
const [revProxyDownloaded, setRevProxyDownloaded] = useState(false);
|
||||
const [delegationDownloaded, setDelegationDownloaded] = useState(false);
|
||||
|
||||
const revProxyBody = <Card.Body>
|
||||
<ReverseProxySampleConfig onClick={() => setRevProxyDownloaded(true)} />
|
||||
<button
|
||||
disabled={!revProxyDownloaded}
|
||||
onClick={() => setBody(body + 1)}
|
||||
>Next</button>
|
||||
</Card.Body >
|
||||
|
||||
const delegationBody = <Card.Body>
|
||||
<DelegationSampleConfig onClick={() => setDelegationDownloaded(true)} />
|
||||
<button
|
||||
disabled={!delegationDownloaded}
|
||||
onClick={() => setBody(body + 1)}
|
||||
>Next</button>
|
||||
</Card.Body>
|
||||
|
||||
|
||||
const finishedBody = <Card.Body>
|
||||
<InlineError error={synapseStartFailed ? "Couldn't start synapse." : undefined}>
|
||||
<button onClick={decoratedOnClick}>Start Synapse</button>
|
||||
</InlineError>
|
||||
<hr />
|
||||
<p>
|
||||
In future use <a href="https://manpages.debian.org/testing/matrix-synapse/synctl.1.en.html">
|
||||
synctl</a> to start and stop synapse. Use the following to start synapse again:
|
||||
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
<code>
|
||||
synctl start {configDir}
|
||||
</code>
|
||||
</pre>
|
||||
</Card.Body>
|
||||
|
||||
const show = [];
|
||||
const [body, setBody] = useState(0);
|
||||
|
||||
|
||||
|
||||
if (tlsType == TLS_TYPES.REVERSE_PROXY) {
|
||||
|
||||
show.push(revProxyBody);
|
||||
|
||||
}
|
||||
if (delegationType != DELEGATION_TYPES.LOCAL) {
|
||||
|
||||
show.push(delegationBody)
|
||||
|
||||
}
|
||||
show.push(finishedBody)
|
||||
|
||||
|
||||
return <Card>
|
||||
<AccordionToggle as={Card.Header} eventKey={COMPLETE_UI}>
|
||||
Setup Complete
|
||||
</AccordionToggle>
|
||||
<Accordion.Collapse eventKey={COMPLETE_UI}>
|
||||
{show[body]}
|
||||
</Accordion.Collapse>
|
||||
</Card>
|
||||
|
||||
}
|
||||
13
synapse_topology/webui/src/js/components/ConfigCompleted.jsx
Normal file
13
synapse_topology/webui/src/js/components/ConfigCompleted.jsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import React, { useState } from 'react';
|
||||
import ContentWrapper from '../containers/ContentWrapper';
|
||||
|
||||
export default () => {
|
||||
|
||||
return <ContentWrapper>
|
||||
<h1>Config selection</h1>
|
||||
<p>The base config has already been setup.</p>
|
||||
<p>If you want to start the installation from scratch please delete the
|
||||
config yaml.</p>
|
||||
</ContentWrapper>;
|
||||
|
||||
}
|
||||
11
synapse_topology/webui/src/js/components/ContentWrapper.jsx
Normal file
11
synapse_topology/webui/src/js/components/ContentWrapper.jsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
|
||||
import style from '../../scss/main.scss';
|
||||
|
||||
export default ({ children }) => {
|
||||
|
||||
|
||||
|
||||
return <div className={style.contentWrapper}>{children}</div>
|
||||
|
||||
}
|
||||
113
synapse_topology/webui/src/js/components/Database.jsx
Normal file
113
synapse_topology/webui/src/js/components/Database.jsx
Normal file
@@ -0,0 +1,113 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import Accordion from 'react-bootstrap/Accordion';
|
||||
import Card from 'react-bootstrap/Card';
|
||||
import useAccordionToggle from 'react-bootstrap/useAccordionToggle';
|
||||
|
||||
import {
|
||||
DATABASE_TYPES,
|
||||
} from '../actions/constants'
|
||||
|
||||
import { DATABASE_UI } from '../reducers/ui-constants';
|
||||
|
||||
import AccordionToggle from '../containers/AccordionToggle';
|
||||
|
||||
import { nextUI } from '../reducers/setup-ui-reducer';
|
||||
import Tabs from 'react-bootstrap/Tabs';
|
||||
import Tab from 'react-bootstrap/Tab';
|
||||
|
||||
export default ({
|
||||
onClick,
|
||||
}) => {
|
||||
|
||||
const defaultDatabase = DATABASE_TYPES.POSTGRES;
|
||||
const [database, setDatabase] = useState(defaultDatabase)
|
||||
|
||||
const hostDefault = "localhost"
|
||||
const [databaseHost, setHost] = useState(hostDefault);
|
||||
const [postgresDatabase, setPostgresDatabase] = useState();
|
||||
const [databaseUsername, setUser] = useState();
|
||||
const [databasePassword, setPassword] = useState();
|
||||
|
||||
const toggle = useAccordionToggle(nextUI(DATABASE_UI));
|
||||
|
||||
return <Card>
|
||||
<AccordionToggle as={Card.Header} eventKey={DATABASE_UI}>
|
||||
Database
|
||||
</AccordionToggle>
|
||||
<Accordion.Collapse eventKey={DATABASE_UI}>
|
||||
<Card.Body>
|
||||
<p>Synapse can use either SQLite3 or Postgres as it's database.</p>
|
||||
<p>Postgres is recommended.</p>
|
||||
|
||||
<Tabs defaultActiveKey={defaultDatabase} onSelect={k => setDatabase(k)}>
|
||||
<Tab eventKey={DATABASE_TYPES.POSTGRES} title={"Postgres"}>
|
||||
This will connect to the given Postgres database via {DATABASE_TYPES.POSTGRES}
|
||||
<p>
|
||||
Host
|
||||
</p>
|
||||
<input
|
||||
type="text"
|
||||
onChange={e => setHost(e.target.value ? e.target.value : hostDefault)}
|
||||
autoFocus
|
||||
placeholder="localhost"
|
||||
/>
|
||||
<p>
|
||||
Database name
|
||||
</p>
|
||||
<input
|
||||
type="text"
|
||||
onChange={e => setPostgresDatabase(e.target.value)}
|
||||
autoFocus
|
||||
placeholder="unspecified"
|
||||
/>
|
||||
<p>
|
||||
User name
|
||||
</p>
|
||||
<input
|
||||
type="text"
|
||||
onChange={e => setUser(e.target.value)}
|
||||
autoFocus
|
||||
placeholder="unspecified"
|
||||
/>
|
||||
<p>
|
||||
Password
|
||||
</p>
|
||||
<input
|
||||
type="text"
|
||||
onChange={e => setPassword(e.target.value)}
|
||||
autoFocus
|
||||
placeholder="unspecified"
|
||||
/>
|
||||
<button
|
||||
className='inputButton'
|
||||
disabled={databaseHost ? undefined : true}
|
||||
onClick={() => {
|
||||
toggle();
|
||||
onClick({
|
||||
databaseType: DATABASE_TYPES.POSTGRES,
|
||||
databaseHost,
|
||||
database: postgresDatabase,
|
||||
databaseUsername,
|
||||
databasePassword,
|
||||
})
|
||||
}}
|
||||
>Use Postgres</button>
|
||||
</Tab>
|
||||
<Tab eventKey={DATABASE_TYPES.SQLITE3} title={DATABASE_TYPES.SQLITE3}>
|
||||
<button
|
||||
className='inputButton'
|
||||
onClick={() => {
|
||||
toggle();
|
||||
onClick({
|
||||
databaseType: DATABASE_TYPES.SQLITE3
|
||||
});
|
||||
}}
|
||||
>Use {DATABASE_TYPES.SQLITE3}</button>
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</Card.Body>
|
||||
</Accordion.Collapse>
|
||||
</Card >
|
||||
|
||||
}
|
||||
165
synapse_topology/webui/src/js/components/DelegationOptions.jsx
Normal file
165
synapse_topology/webui/src/js/components/DelegationOptions.jsx
Normal file
@@ -0,0 +1,165 @@
|
||||
/* eslint-disable max-len */
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import style from '../../scss/main.scss';
|
||||
|
||||
import Accordion from 'react-bootstrap/Accordion';
|
||||
import Card from 'react-bootstrap/Card';
|
||||
import Tabs from 'react-bootstrap/Tabs';
|
||||
import Tab from 'react-bootstrap/Tab';
|
||||
import useAccordionToggle from 'react-bootstrap/useAccordionToggle';
|
||||
|
||||
import { DELEGATION_TYPES } from '../actions/constants';
|
||||
import { DELEGATION_OPTIONS_UI } from '../reducers/ui-constants';
|
||||
import AccordionToggle from '../containers/AccordionToggle';
|
||||
import { nextUI } from '../reducers/setup-ui-reducer';
|
||||
import InlineError from './InlineError';
|
||||
|
||||
export default ({ servername, skip, onClick }) => {
|
||||
|
||||
const defaultType = DELEGATION_TYPES.DNS;
|
||||
const [type, setType] = useState(defaultType);
|
||||
|
||||
const [delegatedServername, setDelegatedServerName] = useState("");
|
||||
|
||||
const [fedPort, setFedPort] = useState("");
|
||||
const [clientPort, setClientPort] = useState("");
|
||||
|
||||
const [clientPortValid, setClientPortValid] = useState(true)
|
||||
const [fedPortValid, setFedPortValid] = useState(true)
|
||||
|
||||
const updateValidity = (port, setValid) => setValid(
|
||||
!port ||
|
||||
(!isNaN(port) && 0 < port && port <= 65535),
|
||||
)
|
||||
|
||||
const onFederationChange = event => {
|
||||
|
||||
const val = event.target.value;
|
||||
setFedPort(val);
|
||||
updateValidity(val, setFedPortValid);
|
||||
|
||||
}
|
||||
|
||||
const onClientChange = event => {
|
||||
|
||||
const val = event.target.value;
|
||||
setClientPort(val);
|
||||
updateValidity(val, setClientPortValid);
|
||||
|
||||
}
|
||||
|
||||
const toggle = useAccordionToggle(nextUI(DELEGATION_OPTIONS_UI));
|
||||
|
||||
const portSelection = <div>
|
||||
<p>Please enter the domain name of the server synapse is installed on.</p>
|
||||
<input
|
||||
type="text"
|
||||
onChange={e => setDelegatedServerName(e.target.value)}
|
||||
autoFocus
|
||||
placeholder="Enter server name"
|
||||
value={delegatedServername}
|
||||
/>
|
||||
<p>
|
||||
Homeserver Port
|
||||
</p>
|
||||
<InlineError error={fedPortValid ? undefined : "Invalid port"}>
|
||||
<input
|
||||
type="text"
|
||||
onChange={onFederationChange}
|
||||
className={fedPortValid ? undefined : "invalid"}
|
||||
autoFocus
|
||||
placeholder="Use Default 8448"
|
||||
value={fedPort}
|
||||
/>
|
||||
</InlineError>
|
||||
<p>
|
||||
Client Port
|
||||
</p>
|
||||
<InlineError error={clientPortValid ? undefined : "Invalid port"}>
|
||||
<input
|
||||
type="text"
|
||||
onChange={onClientChange}
|
||||
className={clientPortValid ? undefined : "invalid"}
|
||||
autoFocus
|
||||
placeholder="Use Default 443"
|
||||
value={clientPort}
|
||||
/>
|
||||
</InlineError>
|
||||
<button disabled={delegatedServername && clientPortValid && fedPortValid ? undefined : true}
|
||||
onClick={() => {
|
||||
|
||||
toggle();
|
||||
onClick(type, delegatedServername, fedPort, clientPort)
|
||||
|
||||
}}
|
||||
>
|
||||
Use {type}
|
||||
</button>
|
||||
</div >
|
||||
|
||||
return <Card>
|
||||
<AccordionToggle as={Card.Header} eventKey={DELEGATION_OPTIONS_UI}>
|
||||
Delegation (optional)
|
||||
|
||||
</AccordionToggle>
|
||||
<Accordion.Collapse eventKey={DELEGATION_OPTIONS_UI}>
|
||||
<Card.Body>
|
||||
<p>
|
||||
If you'd like your synapse to be hosted on a different server to the
|
||||
one known on the network by '{servername}' you can use delegation.
|
||||
<a
|
||||
href="https://github.com/matrix-org/synapse/blob/master/docs/federate.md"
|
||||
target="_blank"
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
If you're not sure if you need delegation, we recommending skipping this step.
|
||||
</p>
|
||||
<button onClick={() => {
|
||||
|
||||
toggle();
|
||||
skip();
|
||||
|
||||
}}>
|
||||
Skip
|
||||
</button>
|
||||
<hr />
|
||||
<p>
|
||||
Other federation servers will connect to {servername}:8448 over the network.
|
||||
</p>
|
||||
<p>
|
||||
There are two forms of delegation:
|
||||
</p>
|
||||
|
||||
<Tabs defaultActiveKey={defaultType} onSelect={k => setType(k)}>
|
||||
<Tab eventKey={DELEGATION_TYPES.DNS} title={DELEGATION_TYPES.DNS}>
|
||||
<p>
|
||||
You will need access to {servername}'s domain zone DNS records.
|
||||
This method also requires the synapse install's server to provide
|
||||
a valid TLS cert for {servername}
|
||||
</p>
|
||||
<p>
|
||||
You will need to add an SRV record to {servername}'s DNS zone. (Once
|
||||
again, we'll print the SRV record out for you later.)
|
||||
</p>
|
||||
{portSelection}
|
||||
</Tab>
|
||||
<Tab eventKey={DELEGATION_TYPES.WELL_KNOWN} title={DELEGATION_TYPES.WELL_KNOWN}>
|
||||
<p>
|
||||
{servername} provides the url
|
||||
https://{servername}/.well-known/matrix/server which gives
|
||||
federating servers information about how to contact the actual
|
||||
server hosting the synapse install. (Don't worry! We'll print out
|
||||
the .well-known file for you later.)
|
||||
</p>
|
||||
{portSelection}
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</Card.Body>
|
||||
</Accordion.Collapse>
|
||||
</Card>
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/* eslint-disable max-len */
|
||||
import React from 'react';
|
||||
|
||||
import ContentWrapper from '../containers/ContentWrapper';
|
||||
import ButtonDisplay from './ButtonDisplay';
|
||||
import DownloadOrCopy from './DownloadOrCopy';
|
||||
import { DELEGATION_TYPES } from '../actions/constants';
|
||||
|
||||
export default ({
|
||||
delegationType,
|
||||
serverConfig,
|
||||
clientConfig,
|
||||
serverConfigFileName,
|
||||
clientConfigFileName,
|
||||
serverName,
|
||||
onClick,
|
||||
}) => {
|
||||
|
||||
if (delegationType == DELEGATION_TYPES.DNS) {
|
||||
|
||||
return <ContentWrapper>
|
||||
<h1 className='setupCompleteTitle'>Configure Delegation</h1>
|
||||
<p>
|
||||
You will need to add the following SRV record to your DNS zone.
|
||||
</p>
|
||||
<pre>
|
||||
<code>
|
||||
{clientConfig}
|
||||
</code>
|
||||
</pre>
|
||||
<DownloadOrCopy content={clientConfig} fileName={clientConfigFileName} onClick={onClick} />
|
||||
</ContentWrapper>
|
||||
|
||||
} else {
|
||||
|
||||
return <ContentWrapper>
|
||||
<h1 className='setupCompleteTitle'>Configure delegation</h1>
|
||||
<p>
|
||||
The delegation configuration needs to take place outside the installer.
|
||||
</p>
|
||||
<p>
|
||||
You'll need to host the following at https://{serverName}/.well-known/matrix/server
|
||||
</p>
|
||||
<pre>
|
||||
<code>
|
||||
{serverConfig}
|
||||
</code>
|
||||
</pre>
|
||||
<DownloadOrCopy content={serverConfig} fileName={serverConfigFileName} onClick={onClick} />
|
||||
<p>
|
||||
You'll also need to host the following at https://{serverName}/.well-known/matrix/client
|
||||
</p>
|
||||
<pre>
|
||||
<code>
|
||||
{clientConfig}
|
||||
</code>
|
||||
</pre>
|
||||
<DownloadOrCopy content={clientConfig} fileName={clientConfigFileName} onClick={onClick} />
|
||||
</ContentWrapper>;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
27
synapse_topology/webui/src/js/components/Done.jsx
Normal file
27
synapse_topology/webui/src/js/components/Done.jsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import Accordion from 'react-bootstrap/Accordion';
|
||||
import Card from 'react-bootstrap/Card';
|
||||
import AccordionToggle from '../containers/AccordionToggle';
|
||||
import { DONE_UI } from '../reducers/ui-constants';
|
||||
|
||||
export default ({ configDir }) => {
|
||||
|
||||
|
||||
return <Card>
|
||||
<AccordionToggle as={Card.Header} eventKey={DONE_UI} >
|
||||
Done
|
||||
</AccordionToggle>
|
||||
<Accordion.Collapse eventKey={DONE_UI}>
|
||||
<Card.Body>
|
||||
<p>
|
||||
Synapse is running!
|
||||
</p>
|
||||
<p>
|
||||
There are many settings to play with in the yaml files in <code>{configDir}</code>.
|
||||
</p>
|
||||
</Card.Body>
|
||||
</Accordion.Collapse>
|
||||
</Card>;
|
||||
|
||||
}
|
||||
43
synapse_topology/webui/src/js/components/DownloadOrCopy.jsx
Normal file
43
synapse_topology/webui/src/js/components/DownloadOrCopy.jsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import ButtonDisplay from './ButtonDisplay';
|
||||
|
||||
const download = (filename, text) => {
|
||||
|
||||
const e = document.createElement('a');
|
||||
e.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
||||
e.setAttribute('download', filename);
|
||||
|
||||
e.style.display = 'none';
|
||||
document.body.appendChild(e);
|
||||
|
||||
e.click();
|
||||
|
||||
document.body.removeChild(e);
|
||||
|
||||
}
|
||||
|
||||
export default ({ content, fileName, onClick = () => undefined }) => {
|
||||
|
||||
const downloadOnClick = () => {
|
||||
|
||||
download(fileName, content);
|
||||
onClick();
|
||||
|
||||
}
|
||||
|
||||
const copyOnClick = () => {
|
||||
|
||||
navigator.clipboard.writeText(content);
|
||||
onClick();
|
||||
|
||||
}
|
||||
|
||||
return <ButtonDisplay>
|
||||
<div className='buttonGroup'>
|
||||
<button onClick={downloadOnClick}>Download</button>
|
||||
<span className='or'>or</span>
|
||||
<button onClick={copyOnClick}>Copy</button>
|
||||
</div>
|
||||
</ButtonDisplay>
|
||||
|
||||
}
|
||||
12
synapse_topology/webui/src/js/components/Error.jsx
Normal file
12
synapse_topology/webui/src/js/components/Error.jsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
import ContentWrapper from '../containers/ContentWrapper';
|
||||
|
||||
export default () => {
|
||||
|
||||
return <ContentWrapper>
|
||||
<h1>Damn!</h1>
|
||||
<p>Has the config server been started?</p>
|
||||
</ContentWrapper>;
|
||||
|
||||
}
|
||||
72
synapse_topology/webui/src/js/components/ExportKeys.jsx
Normal file
72
synapse_topology/webui/src/js/components/ExportKeys.jsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import Accordion from 'react-bootstrap/Accordion';
|
||||
import Card from 'react-bootstrap/Card';
|
||||
import useAccordionToggle from 'react-bootstrap/useAccordionToggle';
|
||||
|
||||
import ButtonDisplay from './ButtonDisplay';
|
||||
import DownloadOrCopy from './DownloadOrCopy';
|
||||
|
||||
import { KEY_EXPORT_UI } from '../reducers/ui-constants';
|
||||
import AccordionToggle from '../containers/AccordionToggle';
|
||||
import { nextUI } from '../reducers/setup-ui-reducer';
|
||||
|
||||
|
||||
export default ({ secretKeyLoaded, secretKey, onClick }) => {
|
||||
|
||||
const [downloadedOrCopied, setDownloadedOrCopied] = useState(false);
|
||||
const toggle = useAccordionToggle(nextUI(KEY_EXPORT_UI));
|
||||
|
||||
const decoratedOnClick = () => {
|
||||
|
||||
setDownloadedOrCopied(false);
|
||||
toggle();
|
||||
onClick();
|
||||
|
||||
}
|
||||
|
||||
let body;
|
||||
|
||||
if (!secretKeyLoaded) {
|
||||
|
||||
body = <Card.Body><p>Generating secret key</p></Card.Body>
|
||||
|
||||
} else {
|
||||
|
||||
body = <Card.Body>
|
||||
<p>
|
||||
Your server uses a secret key to identify itself to other servers. Keep
|
||||
a copy of it to retain ownership of the server name in case the server
|
||||
is inaccessible:
|
||||
</p>
|
||||
<pre><code>{secretKey}</code></pre>
|
||||
<p>
|
||||
Keep a copy of this key somewhere safe by downloading or copying
|
||||
the key to your clipboard to continue.
|
||||
</p>
|
||||
<DownloadOrCopy
|
||||
content={secretKey}
|
||||
fileName="secret_key.txt"
|
||||
onClick={() => setDownloadedOrCopied(true)} />
|
||||
<div className='blockWrapper'>
|
||||
<ButtonDisplay>
|
||||
<button
|
||||
onClick={decoratedOnClick}
|
||||
disabled={!downloadedOrCopied}
|
||||
>Next</button>
|
||||
</ButtonDisplay>
|
||||
</div>
|
||||
</Card.Body>
|
||||
|
||||
}
|
||||
|
||||
return <Card>
|
||||
<AccordionToggle as={Card.Header} eventKey={KEY_EXPORT_UI}>
|
||||
Secret Key
|
||||
</AccordionToggle>
|
||||
<Accordion.Collapse eventKey={KEY_EXPORT_UI}>
|
||||
{body}
|
||||
</Accordion.Collapse>
|
||||
</Card>
|
||||
|
||||
}
|
||||
12
synapse_topology/webui/src/js/components/InlineError.jsx
Normal file
12
synapse_topology/webui/src/js/components/InlineError.jsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
export default ({ error, children }) => {
|
||||
|
||||
return <div
|
||||
className="inlineError"
|
||||
error={error ? "true" : "false"}>
|
||||
{children}
|
||||
{error ? <span>{error}</span> : undefined}
|
||||
</div>
|
||||
|
||||
}
|
||||
11
synapse_topology/webui/src/js/components/Loading.jsx
Normal file
11
synapse_topology/webui/src/js/components/Loading.jsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import React from 'react';
|
||||
|
||||
import ContentWrapper from '../containers/ContentWrapper';
|
||||
|
||||
export default () => {
|
||||
|
||||
return <ContentWrapper>
|
||||
<h1>loading..</h1>
|
||||
</ContentWrapper>;
|
||||
|
||||
}
|
||||
144
synapse_topology/webui/src/js/components/PortSelection.jsx
Normal file
144
synapse_topology/webui/src/js/components/PortSelection.jsx
Normal file
@@ -0,0 +1,144 @@
|
||||
/* eslint-disable max-len */
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import Accordion from 'react-bootstrap/Accordion';
|
||||
import Card from 'react-bootstrap/Card';
|
||||
import useAccordionToggle from 'react-bootstrap/useAccordionToggle';
|
||||
|
||||
import { PORT_SELECTION_UI } from '../reducers/ui-constants';
|
||||
|
||||
import AccordionToggle from '../containers/AccordionToggle';
|
||||
import ContentWrapper from '../containers/ContentWrapper';
|
||||
|
||||
import { nextUI } from '../reducers/setup-ui-reducer';
|
||||
import InlineError from './InlineError';
|
||||
|
||||
export default ({
|
||||
servername,
|
||||
verifyingPorts,
|
||||
fedPortInUse,
|
||||
clientPortInUse,
|
||||
canChangePorts,
|
||||
defaultFedPort,
|
||||
defaultClientPort,
|
||||
onClick,
|
||||
}) => {
|
||||
|
||||
if (verifyingPorts) {
|
||||
|
||||
return <ContentWrapper><h1>Verifying ports.</h1></ContentWrapper>
|
||||
|
||||
}
|
||||
const [fedPort, setFedPort] = useState();
|
||||
const [clientPort, setClientPort] = useState();
|
||||
|
||||
const [clientPortValid, setClientPortValid] = useState(true)
|
||||
const [fedPortValid, setFedPortValid] = useState(true)
|
||||
|
||||
|
||||
const updateValidity = (port, setValid) => setValid(
|
||||
!isNaN(port) && 0 < port && port <= 65535,
|
||||
)
|
||||
|
||||
|
||||
const onFederationChange = event => {
|
||||
|
||||
const val = event.target.value ? event.target.value : defaultFedPort;
|
||||
setFedPort(val);
|
||||
updateValidity(val, setFedPortValid);
|
||||
|
||||
}
|
||||
|
||||
const onClientChange = event => {
|
||||
|
||||
const val = event.target.value ? event.target.value : defaultClientPort;
|
||||
setClientPort(val);
|
||||
updateValidity(val, setClientPortValid);
|
||||
|
||||
}
|
||||
|
||||
const toggle = useAccordionToggle(nextUI(PORT_SELECTION_UI));
|
||||
|
||||
const fedPortError = fedPortInUse ?
|
||||
"This port is in use" :
|
||||
!fedPortValid ? "Invalid port" :
|
||||
undefined;
|
||||
|
||||
const clientPortError = clientPortInUse ?
|
||||
"This port is in use" :
|
||||
!clientPortValid ? "Invalid port" :
|
||||
undefined;
|
||||
|
||||
const fedPortPriv = fedPort ? fedPort < 1024 : defaultFedPort < 1024
|
||||
const clientPortPriv = clientPort ? clientPort < 1024 : defaultClientPort < 1024
|
||||
return <Card>
|
||||
<AccordionToggle as={Card.Header} eventKey={PORT_SELECTION_UI}>
|
||||
{servername ? servername + "'s ports" : "Ports"}
|
||||
</AccordionToggle>
|
||||
<Accordion.Collapse eventKey={PORT_SELECTION_UI}>
|
||||
<Card.Body>
|
||||
|
||||
<p>
|
||||
Synapse will be listening on the following ports on localhost.
|
||||
</p>
|
||||
{
|
||||
canChangePorts ?
|
||||
<p>
|
||||
Since you're using a reverse proxy you can change these to anything you
|
||||
like as long as synapse can bind to them. We recommend not using privileged
|
||||
ports within the range 0 to 1024.
|
||||
</p>
|
||||
:
|
||||
<p>
|
||||
Since you're not using a reverse proxy synapse will have to listen on
|
||||
these ports. If any of these ports are already in use (we'll test them when
|
||||
you click the button) you will either need to reconfigure the ports used on
|
||||
localhost, setup up delegation or use a reverse proxy.
|
||||
</p>
|
||||
}
|
||||
|
||||
<p>
|
||||
We will check that the ports are not in use.
|
||||
</p>
|
||||
<p>
|
||||
Note: we can't check whether privileged ports are in use. If you've
|
||||
set a privileged port <b>we will skip the check for that port</b>.
|
||||
</p>
|
||||
|
||||
<h6>Federation Port</h6>
|
||||
<InlineError error={fedPortError}>
|
||||
<input
|
||||
type="text"
|
||||
onChange={onFederationChange}
|
||||
disabled={canChangePorts ? undefined : true}
|
||||
autoFocus
|
||||
placeholder={defaultFedPort}
|
||||
/>
|
||||
</InlineError>
|
||||
{fedPortPriv ? <p>This is a privileged port.</p> : undefined}
|
||||
<h6>Client Port</h6>
|
||||
<InlineError error={clientPortError}>
|
||||
<input
|
||||
type="text"
|
||||
onChange={onClientChange}
|
||||
disabled={canChangePorts ? undefined : true}
|
||||
autoFocus
|
||||
placeholder={defaultClientPort}
|
||||
/>
|
||||
</InlineError>
|
||||
{clientPortPriv ? <p>This is a privileged port.</p> : undefined}
|
||||
<div>
|
||||
<button
|
||||
disabled={clientPortValid && fedPortValid ? undefined : true}
|
||||
onClick={() => onClick(
|
||||
fedPort ? parseInt(fedPort) : defaultFedPort,
|
||||
clientPort ? parseInt(clientPort) : defaultClientPort,
|
||||
toggle,
|
||||
)}
|
||||
>Verify These Ports</button>
|
||||
</div>
|
||||
</Card.Body>
|
||||
</Accordion.Collapse>
|
||||
</Card>
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
|
||||
import ContentWrapper from '../containers/ContentWrapper';
|
||||
import ButtonDisplay from './ButtonDisplay';
|
||||
import DownloadOrCopy from './DownloadOrCopy';
|
||||
import { REVERSE_PROXY_TYPES } from '../actions/constants';
|
||||
|
||||
export default ({ proxyType, sampleConfig, fileName, onClick }) => {
|
||||
|
||||
return <ContentWrapper>
|
||||
<h1 className='setupCompleteTitle'>Configure the ReverseProxy</h1>
|
||||
<p>
|
||||
It's time for you to setup the reverse proxy outside of this installer.
|
||||
</p>
|
||||
{
|
||||
proxyType == REVERSE_PROXY_TYPES.OTHER ?
|
||||
<p>
|
||||
Here's a sample config for Apache. Since you chose 'other'
|
||||
for your reverse proxy. You'll have to figure it out
|
||||
for yourself. We believe in you.
|
||||
</p>
|
||||
:
|
||||
<p>
|
||||
We can't do it for you
|
||||
but here's the sample configuration for your {proxyType} proxy.
|
||||
</p>
|
||||
}
|
||||
<pre>
|
||||
<code>
|
||||
{sampleConfig}
|
||||
</code>
|
||||
</pre>
|
||||
<DownloadOrCopy content={sampleConfig} fileName={fileName} onClick={onClick} />
|
||||
</ContentWrapper>;
|
||||
|
||||
}
|
||||
67
synapse_topology/webui/src/js/components/ServerName.jsx
Normal file
67
synapse_topology/webui/src/js/components/ServerName.jsx
Normal file
@@ -0,0 +1,67 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import Accordion from 'react-bootstrap/Accordion';
|
||||
import Card from 'react-bootstrap/Card';
|
||||
import { SERVER_NAME_UI } from '../reducers/ui-constants';
|
||||
import AccordionToggle from '../containers/AccordionToggle';
|
||||
import useAccordionToggle from 'react-bootstrap/useAccordionToggle';
|
||||
import { nextUI } from '../reducers/setup-ui-reducer';
|
||||
import InlineError from './InlineError';
|
||||
|
||||
export default ({ onClick }) => {
|
||||
|
||||
const [servername, setServerName] = useState("");
|
||||
const [serverNameValid, setServerNameValid] = useState(true);
|
||||
const validator = /^[0-9a-zA-Z.-]+$/;
|
||||
|
||||
const onChange = event => {
|
||||
|
||||
setServerName(event.target.value);
|
||||
setServerNameValid(validator.test(event.target.value));
|
||||
|
||||
};
|
||||
|
||||
|
||||
const toggle = useAccordionToggle(nextUI(SERVER_NAME_UI));
|
||||
const decoratedOnClick = () => {
|
||||
|
||||
onClick(servername);
|
||||
toggle();
|
||||
|
||||
}
|
||||
|
||||
return <Card>
|
||||
<AccordionToggle as={Card.Header} eventKey={SERVER_NAME_UI} >
|
||||
Name your server
|
||||
</AccordionToggle>
|
||||
<Accordion.Collapse eventKey={SERVER_NAME_UI}>
|
||||
<Card.Body>
|
||||
<p>
|
||||
Your server name usually matches your domain. For example, the
|
||||
matrix.org server is simply called `matrix.org`.
|
||||
</p>
|
||||
<p>
|
||||
Your server name will be used to establish User IDs (e.g.
|
||||
`@user:server.name`) and Room Aliases (e.g. `#room:server.name`).
|
||||
</p>
|
||||
<InlineError error={!serverNameValid ? "The servername may only be alphanumeric characters" : undefined}>
|
||||
<input
|
||||
type="text"
|
||||
onChange={onChange}
|
||||
autoFocus
|
||||
placeholder="Enter server name"
|
||||
/>
|
||||
</InlineError>
|
||||
<div>
|
||||
<button
|
||||
disabled={servername && serverNameValid ? undefined : true}
|
||||
onClick={decoratedOnClick}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
</Card.Body>
|
||||
</Accordion.Collapse>
|
||||
</Card>;
|
||||
|
||||
}
|
||||
48
synapse_topology/webui/src/js/components/StatsReporter.jsx
Normal file
48
synapse_topology/webui/src/js/components/StatsReporter.jsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import Accordion from 'react-bootstrap/Accordion';
|
||||
import Card from 'react-bootstrap/Card';
|
||||
import useAccordionToggle from 'react-bootstrap/useAccordionToggle';
|
||||
|
||||
import { STATS_REPORT_UI } from '../reducers/ui-constants';
|
||||
import AccordionToggle from '../containers/AccordionToggle';
|
||||
import { nextUI } from '../reducers/setup-ui-reducer';
|
||||
|
||||
|
||||
export default ({ onClick }) => {
|
||||
|
||||
const [consent, setConsent] = useState(false);
|
||||
const toggle = useAccordionToggle(nextUI(STATS_REPORT_UI));
|
||||
const decoratedOnClick = () => {
|
||||
|
||||
toggle();
|
||||
onClick(consent);
|
||||
|
||||
}
|
||||
|
||||
return <Card>
|
||||
<AccordionToggle as={Card.Header} eventKey={STATS_REPORT_UI}>
|
||||
Anonymous Statistics
|
||||
</AccordionToggle>
|
||||
<Accordion.Collapse eventKey={STATS_REPORT_UI}>
|
||||
<Card.Body>
|
||||
<p>
|
||||
Would you like to report anonymous statistics to matrix.org?
|
||||
Your server will send anonymised, aggregated statistics to matrix.org
|
||||
on user usage so we can measure the health of the Matrix ecosystem.
|
||||
</p>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
onChange={event => setConsent(event.target.checked)}
|
||||
/>
|
||||
Yes, send anonymous statistics
|
||||
</label>
|
||||
<div className='blockWrapper'>
|
||||
<button onClick={decoratedOnClick}>Next</button>
|
||||
</div>
|
||||
</Card.Body>
|
||||
</Accordion.Collapse>
|
||||
</Card>
|
||||
|
||||
}
|
||||
164
synapse_topology/webui/src/js/components/TLS.jsx
Normal file
164
synapse_topology/webui/src/js/components/TLS.jsx
Normal file
@@ -0,0 +1,164 @@
|
||||
/* eslint-disable max-len */
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import style from '../../scss/main.scss';
|
||||
|
||||
import Accordion from 'react-bootstrap/Accordion';
|
||||
import Card from 'react-bootstrap/Card';
|
||||
import Tabs from 'react-bootstrap/Tabs';
|
||||
import Tab from 'react-bootstrap/Tab';
|
||||
import useAccordionToggle from 'react-bootstrap/useAccordionToggle';
|
||||
|
||||
import { TLS_UI } from '../reducers/ui-constants';
|
||||
import { TLS_TYPES, REVERSE_PROXY_TYPES } from '../actions/constants';
|
||||
import AccordionToggle from '../containers/AccordionToggle';
|
||||
import { nextUI } from '../reducers/setup-ui-reducer';
|
||||
import InlineError from './InlineError';
|
||||
|
||||
const tlsLink = "https://en.wikipedia.org/wiki/Transport_Layer_Security";
|
||||
const apacheLink = "http://httpd.apache.org/";
|
||||
const caddyLink = "https://caddyserver.com/";
|
||||
const haproxyLink = "http://www.haproxy.org/";
|
||||
const nginxLink = "https://www.nginx.com/";
|
||||
|
||||
export default ({
|
||||
testingCertPaths,
|
||||
certPathInvalid,
|
||||
certKeyPathInvalid,
|
||||
onClickCertPath,
|
||||
onClickACME,
|
||||
onClickReverseProxy,
|
||||
}) => {
|
||||
|
||||
const defaultType = TLS_TYPES.REVERSE_PROXY;
|
||||
|
||||
const [certPath, setCertPath] = useState("");
|
||||
const [certKeyPath, setCertKeyPath] = useState("");
|
||||
|
||||
const defaultValue = REVERSE_PROXY_TYPES.NGINX;
|
||||
const [reverseProxy, setReverseProxy] = useState(defaultValue);
|
||||
|
||||
const toggle = useAccordionToggle(nextUI(TLS_UI));
|
||||
|
||||
return <Card>
|
||||
<AccordionToggle as={Card.Header} eventKey={TLS_UI}>
|
||||
TLS
|
||||
</AccordionToggle>
|
||||
<Accordion.Collapse eventKey={TLS_UI}>
|
||||
<Card.Body>
|
||||
<p>
|
||||
Synapse uses TLS to ensure communication between homeservers is
|
||||
secure. To use TLS, you’ll need a TLS certificate. Synapse supports
|
||||
ACME, providing your own certificates, or reverse proxy handling TLS
|
||||
certificates.
|
||||
</p>
|
||||
<Tabs defaultActiveKey={defaultType}>
|
||||
<Tab eventKey={TLS_TYPES.REVERSE_PROXY} title="Reverse Proxy">
|
||||
<p>
|
||||
It is recommended to run Synapse behind a reverse proxy such
|
||||
as <a target="_blank" href={apacheLink}>Apache</a>, <a target="_blank" href={caddyLink}>Caddy</a>, <a target="_blank" href={haproxyLink}>HAProxy</a>, or <a target="_blank" href={nginxLink}>NGiNX</a>.
|
||||
</p>
|
||||
<p>
|
||||
The main benefit to this is that the reverse proxy can listen on
|
||||
the privileged port 443 (which clients like Riot expect to connect
|
||||
to) on behalf of synapse. The incoming traffic is then forwarded
|
||||
to Synapse on a non privileged port.
|
||||
</p>
|
||||
<p>
|
||||
You need root to listen on ports 0 to 1024 inclusive and running
|
||||
synapse with root privileges is <b>strongly discouraged</b>.
|
||||
Reverse proxies are more secure, run with root and pass things on
|
||||
like nobody's business.
|
||||
</p>
|
||||
<p>
|
||||
(Note: you can also have synapse use a non privileged port by
|
||||
using one of the delegation methods mentioned earlier.)
|
||||
</p>
|
||||
<p>
|
||||
If you choose to use a Reverse Proxy we'll provide you with
|
||||
configuration templates later.
|
||||
</p>
|
||||
<p>More information about Reverse Proxies{' '}
|
||||
<a href="https://github.com/matrix-org/synapse/blob/master/docs/reverse_proxy.rst">
|
||||
in the docs</a>.
|
||||
</p>
|
||||
<p>
|
||||
Please choose the reverse proxy you're using. This is just so we can provide
|
||||
you with a template later, if you already know how you're going to set yours
|
||||
up don't worry too much about this.
|
||||
</p>
|
||||
<select defaultValue={defaultValue} onChange={e => setReverseProxy(e.target.value)} >
|
||||
<option value={REVERSE_PROXY_TYPES.APACHE}>Apache</option>
|
||||
<option value={REVERSE_PROXY_TYPES.CADDY}>Caddy</option>
|
||||
<option value={REVERSE_PROXY_TYPES.HAPROXY}>HAProxy</option>
|
||||
<option value={REVERSE_PROXY_TYPES.NGINX}>NGiNX</option>
|
||||
<option value={REVERSE_PROXY_TYPES.OTHER}>Some other Reverse Proxy</option>
|
||||
</select>
|
||||
<div>
|
||||
<button onClick={() => {
|
||||
|
||||
toggle();
|
||||
onClickReverseProxy(reverseProxy)
|
||||
|
||||
}}>
|
||||
Use a reverse proxy with TLS
|
||||
</button>
|
||||
</div>
|
||||
</Tab>
|
||||
<Tab eventKey={TLS_TYPES.ACME} title="ACME">
|
||||
<p>
|
||||
ACME is a protocol that allows TLS certificates to be requested
|
||||
automagically. Synapse supports ACME by requesting certs from
|
||||
Let's Encrypt, which is one of the easiest ways to manage your
|
||||
certificates.
|
||||
</p>
|
||||
<p>
|
||||
If you wish to use ACME you will need access to port 80 which
|
||||
usually requires root privileges. Do not run Synapse as root. Use
|
||||
a Reverse Proxy or Authbind
|
||||
</p>
|
||||
<button onClick={() => {
|
||||
|
||||
toggle();
|
||||
onClickACME()
|
||||
|
||||
}}>Use ACME</button>
|
||||
</Tab>
|
||||
<Tab eventKey={TLS_TYPES.TLS} title="Provide your own TLS certs">
|
||||
<p>
|
||||
Specify a path to or upload TLS certs for the domain.
|
||||
</p>
|
||||
<InlineError error={certPathInvalid ? "The file doesn't exist or can't be accessed." : undefined}>
|
||||
<input
|
||||
className={certPathInvalid ? style.invalidInput : undefined}
|
||||
type="text"
|
||||
placeholder="/path/to/your/cert.pem"
|
||||
value={certPath ? certPath : undefined}
|
||||
onChange={e => setCertPath(e.target.value)}
|
||||
/>
|
||||
</InlineError>
|
||||
|
||||
<p>Please enter path to the cert's key</p>
|
||||
<InlineError error={certKeyPathInvalid ? "The file doesn't exist or can't be accessed." : undefined}>
|
||||
<input
|
||||
className={certKeyPathInvalid ? style.invalidInput : undefined}
|
||||
type="text"
|
||||
placeholder="/path/to/your/cert/key.tls.key"
|
||||
value={certKeyPath ? certKeyPath : undefined}
|
||||
onChange={e => setCertKeyPath(e.target.value)}
|
||||
/>
|
||||
</InlineError>
|
||||
|
||||
<button
|
||||
className="inputButton"
|
||||
disabled={certPath && certKeyPath ? undefined : true}
|
||||
onClick={() => onClickCertPath(certPath, certKeyPath, toggle)}
|
||||
>Use TLS Path</button>
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</Card.Body>
|
||||
</Accordion.Collapse>
|
||||
</Card>
|
||||
|
||||
}
|
||||
108
synapse_topology/webui/src/js/components/UI.jsx
Normal file
108
synapse_topology/webui/src/js/components/UI.jsx
Normal file
@@ -0,0 +1,108 @@
|
||||
import React from 'react';
|
||||
|
||||
import style from '../../scss/main.scss';
|
||||
|
||||
import Accordion from 'react-bootstrap/Accordion';
|
||||
import Card from 'react-bootstrap/Card';
|
||||
|
||||
import {
|
||||
SERVER_NAME_UI,
|
||||
STATS_REPORT_UI,
|
||||
KEY_EXPORT_UI,
|
||||
DELEGATION_OPTIONS_UI,
|
||||
TLS_UI,
|
||||
PORT_SELECTION_UI,
|
||||
REVERSE_PROXY_TEMPLATE_UI,
|
||||
LOADING_UI,
|
||||
ERROR_UI,
|
||||
DELEGATION_TEMPLATE_UI,
|
||||
DATABASE_UI,
|
||||
COMPLETE_UI,
|
||||
SETUP_ORDER,
|
||||
DONE_UI,
|
||||
} from '../reducers/ui-constants';
|
||||
|
||||
import Error from './Error';
|
||||
import Loading from './Loading';
|
||||
|
||||
import BaseIntro from '../containers/BaseIntro';
|
||||
import ServerName from '../containers/ServerName';
|
||||
import StatsReporter from '../containers/StatsReporter';
|
||||
import ExportKeys from '../containers/ExportKeys';
|
||||
import DelegationOptions from '../containers/DelegationOptions';
|
||||
import TLS from '../containers/TLS';
|
||||
import PortSelection from '../containers/PortSelection';
|
||||
import ReverseProxySampleConfig from '../containers/ReverseProxySampleConfig';
|
||||
import DelegationSampleConfig from '../containers/DelegationSampleConfig';
|
||||
import Database from '../containers/Database';
|
||||
import ConfigCompleted from './ConfigCompleted';
|
||||
import CompleteSetup from '../containers/CompleteSetup';
|
||||
import ContentWrapper from '../containers/ContentWrapper';
|
||||
import Done from '../containers/Done';
|
||||
|
||||
const blockMapping = uiBlock => {
|
||||
|
||||
switch (uiBlock) {
|
||||
|
||||
case LOADING_UI:
|
||||
return <Loading key={uiBlock} />
|
||||
case ERROR_UI:
|
||||
return <Error key={uiBlock} />
|
||||
case SERVER_NAME_UI:
|
||||
return <ServerName key={uiBlock} />
|
||||
case STATS_REPORT_UI:
|
||||
return <StatsReporter key={uiBlock} />
|
||||
case KEY_EXPORT_UI:
|
||||
return <ExportKeys key={uiBlock} />
|
||||
case DELEGATION_OPTIONS_UI:
|
||||
return <DelegationOptions key={uiBlock} />
|
||||
case TLS_UI:
|
||||
return <TLS key={uiBlock} />
|
||||
case PORT_SELECTION_UI:
|
||||
return <PortSelection key={uiBlock} />
|
||||
case REVERSE_PROXY_TEMPLATE_UI:
|
||||
return <ReverseProxySampleConfig key={uiBlock} />
|
||||
case DELEGATION_TEMPLATE_UI:
|
||||
return <DelegationSampleConfig key={uiBlock} />
|
||||
case DATABASE_UI:
|
||||
return <Database key={uiBlock} />
|
||||
case COMPLETE_UI:
|
||||
return <CompleteSetup key={uiBlock} />
|
||||
case DONE_UI:
|
||||
return <Done key={uiBlock} />
|
||||
default:
|
||||
return <h1>how did i get here?</h1>
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ({ setupUI, configUI, baseConfig }) => {
|
||||
|
||||
if (!baseConfig.baseConfigChecked) {
|
||||
|
||||
return <Loading />
|
||||
|
||||
}
|
||||
|
||||
if (baseConfig.setupDone) {
|
||||
|
||||
console.log(`switching to ui ${configUI}`);
|
||||
return <ConfigCompleted></ConfigCompleted>
|
||||
|
||||
}
|
||||
|
||||
if (!baseConfig.setupDone) {
|
||||
|
||||
return <ContentWrapper>
|
||||
<Accordion>
|
||||
<BaseIntro />
|
||||
<div style={setupUI.activeBlocks.length ? undefined : { display: "none" }}>
|
||||
{SETUP_ORDER.map(blockMapping)}
|
||||
</div>
|
||||
</Accordion>
|
||||
</ContentWrapper>
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
22
synapse_topology/webui/src/js/containers/AccordionToggle.js
Normal file
22
synapse_topology/webui/src/js/containers/AccordionToggle.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import AccordionToggle from '../components/AccordionToggle';
|
||||
import { resetUI } from '../actions';
|
||||
import { DONE_UI } from '../reducers/ui-constants';
|
||||
|
||||
const mapStateToProps = (state, { eventKey, as, children }) => ({
|
||||
active: state.setupUI.activeBlocks.includes(eventKey) && state.setupUI.activeBlocks[state.setupUI.activeBlocks.length - 1] != DONE_UI,
|
||||
open: state.setupUI.activeBlocks[state.setupUI.activeBlocks.length - 1] == eventKey,
|
||||
eventKey,
|
||||
as,
|
||||
children,
|
||||
});
|
||||
|
||||
const mapDispathToProps = (dispatch, { eventKey }) => ({
|
||||
reset: () => dispatch(resetUI(eventKey)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispathToProps,
|
||||
)(AccordionToggle);
|
||||
19
synapse_topology/webui/src/js/containers/BaseIntro.js
Normal file
19
synapse_topology/webui/src/js/containers/BaseIntro.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import BaseIntro from '../components/BaseIntro';
|
||||
|
||||
import { advanceUI } from '../actions';
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
started: Boolean(state.setupUI.activeBlocks.length),
|
||||
servername: state.baseConfig.servername,
|
||||
});
|
||||
|
||||
const mapDispathToProps = (dispatch) => ({
|
||||
onClick: () => dispatch(advanceUI()),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispathToProps,
|
||||
)(BaseIntro);
|
||||
21
synapse_topology/webui/src/js/containers/CompleteSetup.js
Normal file
21
synapse_topology/webui/src/js/containers/CompleteSetup.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import CompleteSetup from '../components/CompleteSetup';
|
||||
import { writeConfig } from '../actions';
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
tlsType: state.baseConfig.tls,
|
||||
synapseStartFailed: state.baseConfig.synapseStartFailed,
|
||||
delegationType: state.baseConfig.delegationType,
|
||||
configDir: state.baseConfig.configDir,
|
||||
});
|
||||
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onClick: (callback) => dispatch(writeConfig(callback)),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
)(CompleteSetup);
|
||||
15
synapse_topology/webui/src/js/containers/ContentWrapper.js
Normal file
15
synapse_topology/webui/src/js/containers/ContentWrapper.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import ContentWrapper from '../components/ContentWrapper';
|
||||
|
||||
const mapStateToProps = (state, { children }) => ({
|
||||
children,
|
||||
});
|
||||
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
)(ContentWrapper);
|
||||
22
synapse_topology/webui/src/js/containers/Database.js
Normal file
22
synapse_topology/webui/src/js/containers/Database.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Database from '../components/Database';
|
||||
import { setDatabase, advanceUI } from '../actions';
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
};
|
||||
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onClick: databaseConfig => {
|
||||
|
||||
dispatch(setDatabase(databaseConfig));
|
||||
dispatch(advanceUI());
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
mapDispatchToProps,
|
||||
)(Database);
|
||||
@@ -0,0 +1,44 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import DelegationOptions from '../components/DelegationOptions';
|
||||
|
||||
import {
|
||||
setDelegation,
|
||||
advanceUI,
|
||||
setDelegationServername,
|
||||
setDelegationPorts,
|
||||
} from '../actions';
|
||||
|
||||
import { DELEGATION_TYPES } from '../actions/constants';
|
||||
|
||||
const mapStateToProps = (state, { children }) => {
|
||||
|
||||
return {
|
||||
servername: state.baseConfig.servername,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
onClick: (type, servername, fedPort, clientPort) => {
|
||||
|
||||
dispatch(advanceUI());
|
||||
dispatch(setDelegation(type));
|
||||
dispatch(setDelegationServername(servername));
|
||||
dispatch(setDelegationPorts(fedPort, clientPort));
|
||||
|
||||
},
|
||||
|
||||
skip: () => {
|
||||
|
||||
dispatch(advanceUI());
|
||||
dispatch(setDelegation(DELEGATION_TYPES.LOCAL));
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
)(DelegationOptions);
|
||||
@@ -0,0 +1,74 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import DelegationSampleConfig from '../components/DelegationSampleConfig';
|
||||
|
||||
import { advanceUI } from '../actions';
|
||||
|
||||
import DNSConfig from '../templates/dns-srv';
|
||||
import FedWellKnownConfig from '../templates/federation-well-known'
|
||||
import ClientWellKnownConfig from '../templates/client-well-known'
|
||||
import { DELEGATION_TYPES } from '../actions/constants';
|
||||
|
||||
// synapseServerName: state.baseConfig.delegationServerName ? state.baseConfig.delegationServerName : state.baseConfig.servername,
|
||||
|
||||
const serverConfig = state => {
|
||||
|
||||
if (state.delegationType == DELEGATION_TYPES.DNS) {
|
||||
|
||||
return undefined;
|
||||
|
||||
} else {
|
||||
|
||||
return FedWellKnownConfig({
|
||||
synapseServerName: state.delegationServerName,
|
||||
delegationSynapsePort: state.delegationFederationPort ?
|
||||
state.delegationFederationPort :
|
||||
8448,
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const clientConfig = state => {
|
||||
|
||||
if (state.delegationType == DELEGATION_TYPES.WELL_KNOWN) {
|
||||
|
||||
return ClientWellKnownConfig({
|
||||
synapseServerName: state.delegationServerName,
|
||||
delegationClientPort: state.delegationClientPort ?
|
||||
state.delegationClientPort :
|
||||
443,
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
return DNSConfig({
|
||||
serverName: state.servername,
|
||||
synapseServerName: state.delegationServerName,
|
||||
delegationClientPort: state.delegationClientPort ?
|
||||
state.delegationClientPort :
|
||||
443,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
delegationType: state.baseConfig.delegationType,
|
||||
serverConfig: serverConfig(state.baseConfig),
|
||||
clientConfig: clientConfig(state.baseConfig),
|
||||
serverConfigFileName: `${state.baseConfig.servername}_delegation.conf`,
|
||||
clientConfigFileName: `${state.baseConfig.servername}_client_delegation.conf`,
|
||||
serverName: state.baseConfig.servername,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch, { onClick }) => ({
|
||||
onClick,
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
)(DelegationSampleConfig);
|
||||
16
synapse_topology/webui/src/js/containers/Done.js
Normal file
16
synapse_topology/webui/src/js/containers/Done.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import Done from '../components/Done';
|
||||
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
configDir: state.baseConfig.configDir,
|
||||
});
|
||||
|
||||
const mapDispathToProps = (dispatch) => ({
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispathToProps,
|
||||
)(Done);
|
||||
25
synapse_topology/webui/src/js/containers/ExportKeys.js
Normal file
25
synapse_topology/webui/src/js/containers/ExportKeys.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import ExportKeys from '../components/ExportKeys';
|
||||
|
||||
import { advanceUI } from '../actions';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
|
||||
const secretKeyLoaded = state.baseConfig.secretKeyLoaded;
|
||||
const secretKey = state.baseConfig.secretKey;
|
||||
return {
|
||||
secretKeyLoaded,
|
||||
secretKey,
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onClick: () => dispatch(advanceUI()),
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
)(ExportKeys);
|
||||
59
synapse_topology/webui/src/js/containers/PortSelection.js
Normal file
59
synapse_topology/webui/src/js/containers/PortSelection.js
Normal file
@@ -0,0 +1,59 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import PortSelection from '../components/PortSelection';
|
||||
|
||||
import { setSynapsePorts } from '../actions';
|
||||
import { TLS_TYPES } from '../actions/constants';
|
||||
|
||||
const defaultFedPort = state => {
|
||||
|
||||
if (state.tls == TLS_TYPES.REVERSE_PROXY) {
|
||||
|
||||
return 8008;
|
||||
|
||||
}
|
||||
|
||||
return state.delegationFederationPort ? state.delegationFederationPort : 8448;
|
||||
|
||||
}
|
||||
|
||||
const defaultClientPort = state => {
|
||||
|
||||
if (state.tls == TLS_TYPES.REVERSE_PROXY) {
|
||||
|
||||
return 8008;
|
||||
|
||||
}
|
||||
|
||||
return state.delegationFederationPort ?
|
||||
state.delegationFederationPort :
|
||||
443;
|
||||
|
||||
}
|
||||
|
||||
const mapStateToProps = ({ baseConfig }) => ({
|
||||
servername: baseConfig.servername,
|
||||
verifyingPorts: baseConfig.verifyingPorts,
|
||||
fedPortInUse: baseConfig.synapseFederationPortFree != undefined ?
|
||||
!baseConfig.synapseFederationPortFree :
|
||||
false,
|
||||
clientPortInUse: baseConfig.synapseClientPortFree != undefined ?
|
||||
!baseConfig.synapseClientPortFree :
|
||||
false,
|
||||
canChangePorts: baseConfig.tls == TLS_TYPES.REVERSE_PROXY,
|
||||
defaultFedPort: defaultFedPort(baseConfig),
|
||||
defaultClientPort: defaultClientPort(baseConfig),
|
||||
});
|
||||
|
||||
const mapDispathToProps = (dispatch) => ({
|
||||
onClick: (fedPort, clientPort, callback) => {
|
||||
|
||||
dispatch(setSynapsePorts(fedPort, clientPort, callback));
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispathToProps,
|
||||
)(PortSelection);
|
||||
@@ -0,0 +1,58 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import ReverseProxySampleConfig from '../components/ReverseProxySampleConfig';
|
||||
|
||||
import { REVERSE_PROXY_TYPES } from '../actions/constants';
|
||||
|
||||
import apacheConfig from '../templates/apache';
|
||||
import caddyConfig from '../templates/caddy';
|
||||
import haproxyConfig from '../templates/haproxy';
|
||||
import nginxConfig from '../templates/nginx';
|
||||
|
||||
const sampleConfig = reverseProxyType => {
|
||||
|
||||
switch (reverseProxyType) {
|
||||
|
||||
case REVERSE_PROXY_TYPES.APACHE:
|
||||
return apacheConfig;
|
||||
case REVERSE_PROXY_TYPES.CADDY:
|
||||
return caddyConfig;
|
||||
case REVERSE_PROXY_TYPES.HAPROXY:
|
||||
return haproxyConfig;
|
||||
case REVERSE_PROXY_TYPES.NGINX:
|
||||
return nginxConfig;
|
||||
case REVERSE_PROXY_TYPES.OTHER:
|
||||
return otherConfig;
|
||||
default:
|
||||
return () => { }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
proxyType: state.baseConfig.reverseProxy,
|
||||
sampleConfig: sampleConfig(state.baseConfig.reverseProxy)({
|
||||
delegationFedPort: state.baseConfig.delegationFederationPort ?
|
||||
state.baseConfig.delegationFederationPort :
|
||||
8448,
|
||||
delegationClientPort: state.baseConfig.delegationClientPort ?
|
||||
state.baseConfig.delegationClientPort :
|
||||
443,
|
||||
fedPort: state.baseConfig.synapseFederationPort,
|
||||
clientPort: state.baseConfig.synapseClientPort,
|
||||
synapseServerName: state.baseConfig.delegationServerName ?
|
||||
state.baseConfig.delegationServerName :
|
||||
state.baseConfig.servername,
|
||||
}),
|
||||
fileName: "synapse_reverse_proxy.conf",
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch, { onClick }) => ({
|
||||
onClick,
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
)(ReverseProxySampleConfig);
|
||||
24
synapse_topology/webui/src/js/containers/ServerName.js
Normal file
24
synapse_topology/webui/src/js/containers/ServerName.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import ServerName from '../components/ServerName';
|
||||
|
||||
import { advanceUI, setServername, generateSecretKeys } from '../actions';
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
|
||||
});
|
||||
|
||||
const mapDispathToProps = (dispatch) => ({
|
||||
onClick: servername => {
|
||||
|
||||
dispatch(advanceUI());
|
||||
dispatch(setServername(servername));
|
||||
dispatch(generateSecretKeys(servername));
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
mapDispathToProps,
|
||||
)(ServerName);
|
||||
23
synapse_topology/webui/src/js/containers/StatsReporter.js
Normal file
23
synapse_topology/webui/src/js/containers/StatsReporter.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import StatsReporter from '../components/StatsReporter';
|
||||
|
||||
import { advanceUI, setStats } from '../actions';
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
|
||||
});
|
||||
|
||||
const mapDispathToProps = (dispatch) => ({
|
||||
onClick: consent => {
|
||||
|
||||
dispatch(advanceUI());
|
||||
dispatch(setStats(consent));
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
mapDispathToProps,
|
||||
)(StatsReporter);
|
||||
52
synapse_topology/webui/src/js/containers/TLS.js
Normal file
52
synapse_topology/webui/src/js/containers/TLS.js
Normal file
@@ -0,0 +1,52 @@
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import TLS from '../components/TLS';
|
||||
|
||||
import {
|
||||
advanceUI,
|
||||
setTls,
|
||||
setTlsCertPaths,
|
||||
setTlsCertFiles,
|
||||
setReverseProxy,
|
||||
} from '../actions';
|
||||
|
||||
import { TLS_TYPES } from '../actions/constants';
|
||||
|
||||
const mapStateToProps = (state, ownProps) => ({
|
||||
testingCertPaths: state.baseConfig.testingCertPaths,
|
||||
uploadingCertPaths: state.baseConfig.uploadingCerts,
|
||||
certPathInvalid: state.baseConfig.certPathInvalid,
|
||||
certKeyPathInvalid: state.baseConfig.certKeyPathInvalid,
|
||||
});
|
||||
|
||||
const mapDispathToProps = (dispatch) => ({
|
||||
onClickACME: () => {
|
||||
|
||||
dispatch(advanceUI(TLS_TYPES.ACME));
|
||||
dispatch(setTls(TLS_TYPES.ACME));
|
||||
|
||||
},
|
||||
onClickReverseProxy: proxyType => {
|
||||
|
||||
dispatch(advanceUI());
|
||||
dispatch(setTls(TLS_TYPES.REVERSE_PROXY))
|
||||
dispatch(setReverseProxy(proxyType))
|
||||
|
||||
},
|
||||
onClickCertPath: (certPath, certKeyPath, callback) => {
|
||||
|
||||
dispatch(setTlsCertPaths(certPath, certKeyPath, callback));
|
||||
|
||||
},
|
||||
onClickCertUpload: (tlsCertFile, tlsKeyFile, callback) => {
|
||||
|
||||
dispatch(setTlsCertFiles(tlsCertFile, tlsKeyFile));
|
||||
callback();
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispathToProps,
|
||||
)(TLS)
|
||||
18
synapse_topology/webui/src/js/containers/UI.js
Normal file
18
synapse_topology/webui/src/js/containers/UI.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import { connect } from 'react-redux';
|
||||
import UI from '../components/UI';
|
||||
|
||||
const mapStateToProps = ({ setupDone, setupUI, configUI, baseConfig }) => ({
|
||||
setupDone,
|
||||
setupUI,
|
||||
configUI,
|
||||
baseConfig,
|
||||
})
|
||||
|
||||
|
||||
const mapDispathToProps = (dispatch, ownProps) => ({
|
||||
|
||||
})
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
)(UI)
|
||||
25
synapse_topology/webui/src/js/index.jsx
Normal file
25
synapse_topology/webui/src/js/index.jsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
import { createStore, applyMiddleware } from 'redux'
|
||||
import thunk from 'redux-thunk';
|
||||
import rootReducer from './reducers';
|
||||
import UI from './containers/UI';
|
||||
|
||||
import { startup } from './actions';
|
||||
|
||||
const store = createStore(
|
||||
rootReducer,
|
||||
applyMiddleware(thunk),
|
||||
//+ window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
|
||||
);
|
||||
|
||||
store.dispatch(startup());
|
||||
|
||||
render(
|
||||
<Provider store={store}>
|
||||
{/* <img className={style.logo} src={logo} /> */}
|
||||
<UI />
|
||||
</Provider>,
|
||||
document.body,
|
||||
);
|
||||
147
synapse_topology/webui/src/js/reducers/base-config-reducer.js
Normal file
147
synapse_topology/webui/src/js/reducers/base-config-reducer.js
Normal file
@@ -0,0 +1,147 @@
|
||||
import {
|
||||
SET_SERVERNAME,
|
||||
SET_STATS,
|
||||
SET_SECRET_KEY,
|
||||
GETTING_SECRET_KEY,
|
||||
SET_DELEGATION,
|
||||
SET_DELEGATION_PORTS,
|
||||
SET_DELEGATION_SERVERNAME,
|
||||
SET_REVERSE_PROXY,
|
||||
SET_TLS,
|
||||
TESTING_TLS_CERT_PATHS,
|
||||
SET_TLS_CERT_PATHS,
|
||||
SET_TLS_CERT_PATHS_VALIDITY,
|
||||
SET_TLS_CERT_FILES,
|
||||
UPLOADING_TLS_CERT_PATHS,
|
||||
TESTING_SYNAPSE_PORTS,
|
||||
SET_SYNAPSE_PORTS,
|
||||
SET_SYNAPSE_PORTS_FREE,
|
||||
SET_DATABASE,
|
||||
SET_CONFIG_DIR,
|
||||
BASE_CONFIG_CHECKED,
|
||||
SYNAPSE_START_FAILED,
|
||||
} from "../actions/types";
|
||||
|
||||
export default (state, action) => {
|
||||
|
||||
switch (action.type) {
|
||||
|
||||
case BASE_CONFIG_CHECKED:
|
||||
return {
|
||||
...state,
|
||||
baseConfigChecked: true,
|
||||
setupDone: action.setupDone,
|
||||
}
|
||||
case SET_SERVERNAME:
|
||||
return {
|
||||
...state,
|
||||
servername: action.servername,
|
||||
}
|
||||
case SET_STATS:
|
||||
return {
|
||||
...state,
|
||||
reportStats: action.consent,
|
||||
}
|
||||
case GETTING_SECRET_KEY:
|
||||
return {
|
||||
...state,
|
||||
secretKeyLoaded: false,
|
||||
}
|
||||
case SET_SECRET_KEY:
|
||||
return {
|
||||
...state,
|
||||
secretKeyLoaded: true,
|
||||
secretKey: action.key,
|
||||
};
|
||||
case SET_DELEGATION:
|
||||
return {
|
||||
...state,
|
||||
delegationType: action.delegationType,
|
||||
}
|
||||
case SET_DELEGATION_PORTS:
|
||||
return {
|
||||
...state,
|
||||
delegationFederationPort: action.federationPort,
|
||||
delegationClientPort: action.clientPort,
|
||||
}
|
||||
case SET_DELEGATION_SERVERNAME:
|
||||
return {
|
||||
...state,
|
||||
delegationServername: action.servername,
|
||||
}
|
||||
case SET_REVERSE_PROXY:
|
||||
return {
|
||||
...state,
|
||||
reverseProxy: action.proxyType,
|
||||
}
|
||||
case SET_TLS:
|
||||
return {
|
||||
...state,
|
||||
tls: action.tlsType,
|
||||
}
|
||||
case TESTING_TLS_CERT_PATHS:
|
||||
return {
|
||||
...state,
|
||||
testingCertPaths: action.testing,
|
||||
}
|
||||
case SET_TLS_CERT_PATHS_VALIDITY:
|
||||
return {
|
||||
...state,
|
||||
certPathInvalid: action.certPathInvalid,
|
||||
certKeyPathInvalid: action.certKeyPathInvalid,
|
||||
}
|
||||
case SET_TLS_CERT_PATHS:
|
||||
return {
|
||||
...state,
|
||||
tlsCertPath: action.certPath,
|
||||
tlsCertKeyPath: action.certKeyPath,
|
||||
}
|
||||
case SET_TLS_CERT_FILES:
|
||||
return {
|
||||
...state,
|
||||
tlsCertFile: action.tlsCertFile,
|
||||
tlsCertKeyFile: action.tlsCerKeyFile,
|
||||
}
|
||||
case UPLOADING_TLS_CERT_PATHS:
|
||||
return {
|
||||
...state,
|
||||
uploadingCerts: action.uploading,
|
||||
}
|
||||
case TESTING_SYNAPSE_PORTS:
|
||||
return {
|
||||
...state,
|
||||
verifyingports: action.verifying,
|
||||
}
|
||||
case SET_SYNAPSE_PORTS:
|
||||
return {
|
||||
...state,
|
||||
synapseFederationPort: action.federationPort,
|
||||
synapseClientPort: action.clientPort,
|
||||
}
|
||||
case SET_SYNAPSE_PORTS_FREE:
|
||||
return {
|
||||
...state,
|
||||
synapseFederationPortFree: action.synapseFederationPortFree,
|
||||
synapseClientPortFree: action.synapseClientPortFree,
|
||||
}
|
||||
case SET_DATABASE:
|
||||
return {
|
||||
...state,
|
||||
...action.databaseConfig,
|
||||
}
|
||||
case SET_CONFIG_DIR:
|
||||
return {
|
||||
...state,
|
||||
configDir: action.configDir,
|
||||
}
|
||||
case SYNAPSE_START_FAILED:
|
||||
return {
|
||||
...state,
|
||||
synapseStartFailed: true,
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
21
synapse_topology/webui/src/js/reducers/config-ui-reducer.js
Normal file
21
synapse_topology/webui/src/js/reducers/config-ui-reducer.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const ADVANCED_CONFIG_UI_COMPONENTS = {
|
||||
CONFIG_SELECTION_UI: "config_selection_ui",
|
||||
};
|
||||
|
||||
export default ({ configUI, baseConfig }, action) => {
|
||||
|
||||
if (!baseConfig.baseConfigChecked) {
|
||||
|
||||
return configUI;
|
||||
|
||||
};
|
||||
|
||||
if (!baseConfig.setupDone) {
|
||||
|
||||
return configUI;
|
||||
|
||||
};
|
||||
|
||||
return configUI;
|
||||
|
||||
}
|
||||
75
synapse_topology/webui/src/js/reducers/index.js
Normal file
75
synapse_topology/webui/src/js/reducers/index.js
Normal file
@@ -0,0 +1,75 @@
|
||||
import baseConfigReducer from './base-config-reducer';
|
||||
|
||||
import configUIReducer from './config-ui-reducer';
|
||||
import setupUIReducer from './setup-ui-reducer';
|
||||
|
||||
|
||||
import { uiStateMapping } from './state';
|
||||
import { BACK_UI } from '../actions/types';
|
||||
|
||||
export default (state = {
|
||||
setupUI: {
|
||||
activeBlocks: [],
|
||||
},
|
||||
configUI: {
|
||||
},
|
||||
baseConfig: {
|
||||
baseConfigChecked: false,
|
||||
},
|
||||
}, action) => {
|
||||
|
||||
const setupUI = setupUIReducer(state, action);
|
||||
|
||||
const rState = {
|
||||
configUI: configUIReducer(state, action),
|
||||
setupUI,
|
||||
baseConfig: filterBaseConfig(
|
||||
baseConfigReducer(state.baseConfig, action),
|
||||
action,
|
||||
setupUI.activeBlocks.slice(0, setupUI.activeBlocks.length - 1),
|
||||
),
|
||||
}
|
||||
|
||||
console.log(action);
|
||||
console.log(rState);
|
||||
|
||||
return rState;
|
||||
|
||||
};
|
||||
|
||||
const filterBaseConfig = (baseConfig, action, activeBlocks) => {
|
||||
|
||||
if (action.type == BACK_UI) {
|
||||
|
||||
return filterObj(
|
||||
baseConfig,
|
||||
Object.values(
|
||||
filterObj(
|
||||
uiStateMapping,
|
||||
[...activeBlocks, "base"]),
|
||||
).flat(),
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
return baseConfig;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const filterObj = (object, filterList) => {
|
||||
|
||||
return Object.keys(object)
|
||||
.filter(key => filterList.includes(key))
|
||||
.reduce((obj, key) => {
|
||||
|
||||
obj[key] = object[key];
|
||||
return obj;
|
||||
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
57
synapse_topology/webui/src/js/reducers/setup-ui-reducer.js
Normal file
57
synapse_topology/webui/src/js/reducers/setup-ui-reducer.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import { ADVANCE_UI, BACK_UI, BASE_CONFIG_CHECKED } from '../actions/types';
|
||||
import {
|
||||
SETUP_ORDER,
|
||||
} from './ui-constants';
|
||||
|
||||
|
||||
const newActiveBlocks = activeBlocks => {
|
||||
|
||||
return SETUP_ORDER.slice(0, activeBlocks.length + 1)
|
||||
|
||||
}
|
||||
|
||||
export default ({ setupUI, baseConfig }, action) => {
|
||||
|
||||
if (!baseConfig.baseConfigChecked) {
|
||||
|
||||
return setupUI;
|
||||
|
||||
}
|
||||
if (baseConfig.setupDone) {
|
||||
|
||||
return setupUI;
|
||||
|
||||
}
|
||||
switch (action.type) {
|
||||
|
||||
case ADVANCE_UI:
|
||||
return {
|
||||
activeBlocks: newActiveBlocks(setupUI.activeBlocks),
|
||||
};
|
||||
case BACK_UI:
|
||||
return {
|
||||
activeBlocks: resetUI(setupUI.activeBlocks, action.ui),
|
||||
};
|
||||
default:
|
||||
return setupUI;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const nextUI = current => SETUP_ORDER[SETUP_ORDER.lastIndexOf(current) + 1]
|
||||
|
||||
export const resetUI = (activeBlocks, destinationBlock) => {
|
||||
|
||||
const indexOfDest = SETUP_ORDER.indexOf(destinationBlock);
|
||||
|
||||
if (indexOfDest >= activeBlocks.length) {
|
||||
|
||||
// The index is in the future
|
||||
return activeBlocks;
|
||||
|
||||
}
|
||||
|
||||
return activeBlocks.slice(0, indexOfDest + 1);
|
||||
|
||||
}
|
||||
129
synapse_topology/webui/src/js/reducers/state.js
Normal file
129
synapse_topology/webui/src/js/reducers/state.js
Normal file
@@ -0,0 +1,129 @@
|
||||
import {
|
||||
SERVER_NAME_UI,
|
||||
STATS_REPORT_UI,
|
||||
KEY_EXPORT_UI,
|
||||
DELEGATION_OPTIONS_UI,
|
||||
PORT_SELECTION_UI,
|
||||
DATABASE_UI,
|
||||
COMPLETE_UI,
|
||||
TLS_UI,
|
||||
} from './ui-constants';
|
||||
|
||||
const setupUI = "setupUI";
|
||||
const activeBlocks = "activeBlocks";
|
||||
const configUI = "configUI";
|
||||
const baseConfig = "baseConfig";
|
||||
const setupDone = "setupDone";
|
||||
const baseConfigChecked = "baseConfigChecked";
|
||||
const servername = "servername";
|
||||
const reportStats = "reportStats";
|
||||
const secretKeyLoaded = "secretKeyLoaded";
|
||||
const secretKey = "secretKey";
|
||||
const delegationType = "delegationType";
|
||||
const delegationServerName = "delegationServerName";
|
||||
const delegationFederationPort = "delegationFederationPort";
|
||||
const delegationClientPort = "delegationClientPort";
|
||||
const reverseProxy = "reverseProxy";
|
||||
const tls = "tls";
|
||||
const testingCertPaths = "testingCertPaths";
|
||||
const uploadingCerts = "uploadingCerts";
|
||||
const certPathInvalid = "certPathInvalid";
|
||||
const certKeyPathInvalid = "certKeyPathInvalid";
|
||||
const tlsCertPath = "tlsCertPath";
|
||||
const tlsCertKeyPath = "tlsCertKeyPath";
|
||||
const tlsCertFile = "tlsCertFile";
|
||||
const tlsCertKeyFile = "tlsCertKeyFile";
|
||||
const tlsPath = "tlsPath";
|
||||
const verifyingPorts = "verifyingPorts";
|
||||
const synapseFederationPortFree = "synapseFederationPortFree";
|
||||
const synapseClientPortFree = "synapseClientPortFree";
|
||||
const synapseFederationPort = "synapseFederationPort";
|
||||
const synapseClientPort = "synapseClientPort";
|
||||
const databaseConf = "databaseConf";
|
||||
const configDir = "configDir";
|
||||
|
||||
const state = {
|
||||
[setupUI]: {
|
||||
[activeBlocks]: ["block1"],
|
||||
},
|
||||
[configUI]: {
|
||||
|
||||
},
|
||||
[baseConfig]: {
|
||||
[setupDone]: true,
|
||||
[baseConfigChecked]: false,
|
||||
[configDir]: "sadfasdf",
|
||||
[servername]: "server_name",
|
||||
[reportStats]: false,
|
||||
[secretKeyLoaded]: false,
|
||||
[secretKey]: "asdfsadf",
|
||||
[delegationType]: "local|well_known|DNS_SRV",
|
||||
[delegationServerName]: "name",
|
||||
[delegationFederationPort]: "\"\"|325",
|
||||
[delegationClientPort]: "\"\"|325",
|
||||
[reverseProxy]: "nginx|caddy|apache|haproxy|other|none",
|
||||
[tls]: "acme|tls|reverseproxy",
|
||||
[testingCertPaths]: true,
|
||||
[uploadingCerts]: true,
|
||||
[certPathInvalid]: true,
|
||||
[certKeyPathInvalid]: true,
|
||||
[tlsCertPath]: "sadfaf",
|
||||
[tlsCertKeyPath]: "sdfasdf",
|
||||
[tlsCertFile]: "sadfa;dlf;sad;fkla;sdlfjkas;dlfkjas;dflkja;sdfkljadf ------",
|
||||
[tlsCertKeyFile]: "sadfa;dlf;sad;fkla;sdlfjkas;dlfkjas;dflkja;sdfkljadf ------",
|
||||
[verifyingPorts]: true,
|
||||
[synapseFederationPortFree]: true,
|
||||
[synapseClientPortFree]: true,
|
||||
[synapseFederationPort]: 1234,
|
||||
[synapseClientPort]: 1234,
|
||||
[databaseConf]: "{dadtabaseType, databaseUsername, databasePassword, database}",
|
||||
},
|
||||
}
|
||||
|
||||
export const uiStateMapping = {
|
||||
base: [
|
||||
setupDone,
|
||||
baseConfigChecked,
|
||||
configDir,
|
||||
],
|
||||
[SERVER_NAME_UI]: [
|
||||
servername,
|
||||
secretKeyLoaded,
|
||||
secretKey,
|
||||
],
|
||||
[STATS_REPORT_UI]: [
|
||||
reportStats,
|
||||
],
|
||||
[KEY_EXPORT_UI]: [
|
||||
],
|
||||
[DELEGATION_OPTIONS_UI]: [
|
||||
delegationType,
|
||||
delegationServerName,
|
||||
delegationClientPort,
|
||||
delegationFederationPort,
|
||||
],
|
||||
[TLS_UI]: [
|
||||
tls,
|
||||
reverseProxy,
|
||||
testingCertPaths,
|
||||
uploadingCerts,
|
||||
certPathInvalid,
|
||||
certKeyPathInvalid,
|
||||
tlsCertPath,
|
||||
tlsCertKeyPath,
|
||||
tlsCertFile,
|
||||
tlsCertKeyFile,
|
||||
],
|
||||
[PORT_SELECTION_UI]: [
|
||||
verifyingPorts,
|
||||
synapseClientPort,
|
||||
synapseFederationPort,
|
||||
synapseClientPortFree,
|
||||
synapseFederationPortFree,
|
||||
],
|
||||
[DATABASE_UI]: [
|
||||
databaseConf,
|
||||
],
|
||||
[COMPLETE_UI]: [
|
||||
],
|
||||
}
|
||||
35
synapse_topology/webui/src/js/reducers/ui-constants.js
Normal file
35
synapse_topology/webui/src/js/reducers/ui-constants.js
Normal file
@@ -0,0 +1,35 @@
|
||||
// Setup
|
||||
export const SERVER_NAME_UI = "server_name_ui";
|
||||
export const STATS_REPORT_UI = "stats_report_ui";
|
||||
export const KEY_EXPORT_UI = "key_export_ui";
|
||||
export const DELEGATION_OPTIONS_UI = "delegation_options_ui";
|
||||
export const TLS_UI = "tls_ui";
|
||||
export const PORT_SELECTION_UI = "port_selection_ui";
|
||||
export const REVERSE_PROXY_TEMPLATE_UI = "reverse_proxy_tamplate_ui";
|
||||
export const DELEGATION_TEMPLATE_UI = "delegation_tamplate_ui";
|
||||
export const DATABASE_UI = "database_ui";
|
||||
export const COMPLETE_UI = "complete_ui";
|
||||
export const DONE_UI = "done_ui";
|
||||
|
||||
// Setup order
|
||||
export const SETUP_ORDER = [
|
||||
SERVER_NAME_UI,
|
||||
STATS_REPORT_UI,
|
||||
KEY_EXPORT_UI,
|
||||
DELEGATION_OPTIONS_UI,
|
||||
TLS_UI,
|
||||
PORT_SELECTION_UI,
|
||||
DATABASE_UI,
|
||||
COMPLETE_UI,
|
||||
DONE_UI,
|
||||
];
|
||||
|
||||
|
||||
// Config
|
||||
export const CONFIG_SELECTION_UI = "config_selection_ui";
|
||||
|
||||
// Loading screen:
|
||||
export const LOADING_UI = "loading_ui";
|
||||
|
||||
// Error screen:
|
||||
export const ERROR_UI = "error_ui";
|
||||
25
synapse_topology/webui/src/js/templates/apache.js
Normal file
25
synapse_topology/webui/src/js/templates/apache.js
Normal file
@@ -0,0 +1,25 @@
|
||||
export default ({
|
||||
delegationFedPort,
|
||||
delegationClientPort,
|
||||
fedPort,
|
||||
clientPort,
|
||||
synapseServerName,
|
||||
}) => `
|
||||
<VirtualHost *:${delegationClientPort}>
|
||||
SSLEngine on
|
||||
ServerName ${synapseServerName};
|
||||
|
||||
AllowEncodedSlashes NoDecode
|
||||
ProxyPass /_matrix http://127.0.0.1:${clientPort}/_matrix nocanon
|
||||
ProxyPassReverse /_matrix http://127.0.0.1:${clientPort}/_matrix
|
||||
</VirtualHost>
|
||||
|
||||
<VirtualHost *:${delegationFedPort}>
|
||||
SSLEngine on
|
||||
ServerName ${synapseServerName};
|
||||
|
||||
AllowEncodedSlashes NoDecode
|
||||
ProxyPass /_matrix http://127.0.0.1:${fedPort}/_matrix nocanon
|
||||
ProxyPassReverse /_matrix http://127.0.0.1:${fedPort}/_matrix
|
||||
</VirtualHost>
|
||||
`
|
||||
17
synapse_topology/webui/src/js/templates/caddy.js
Normal file
17
synapse_topology/webui/src/js/templates/caddy.js
Normal file
@@ -0,0 +1,17 @@
|
||||
export default ({
|
||||
delegationFedPort,
|
||||
delegationClientPort,
|
||||
fedPort,
|
||||
clientPort,
|
||||
synapseServerName,
|
||||
}) => `${synapseServerName}:${delegationClientPort} {
|
||||
proxy /_matrix http://localhost:${clientPort} {
|
||||
transparent
|
||||
}
|
||||
}
|
||||
|
||||
${synapseServerName}:${delegationFedPort} {
|
||||
proxy / http://localhost:${fedPort} {
|
||||
transparent
|
||||
}
|
||||
}`
|
||||
13
synapse_topology/webui/src/js/templates/client-well-known.js
Normal file
13
synapse_topology/webui/src/js/templates/client-well-known.js
Normal file
@@ -0,0 +1,13 @@
|
||||
/* eslint-disable max-len */
|
||||
export default ({
|
||||
synapseServerName,
|
||||
delegationClientPort,
|
||||
}) => `{
|
||||
"m.homeserver": {
|
||||
"base_url": "https://${synapseServerName}${delegationClientPort ? `:${delegationClientPort}` : ""}"
|
||||
},
|
||||
}`
|
||||
// TODO: Maybe include this?
|
||||
// "m.identity_server": {
|
||||
// "base_url": "https://identity.example.com"
|
||||
// },
|
||||
9
synapse_topology/webui/src/js/templates/dns-srv.js
Normal file
9
synapse_topology/webui/src/js/templates/dns-srv.js
Normal file
@@ -0,0 +1,9 @@
|
||||
/* eslint-disable max-len */
|
||||
export default ({
|
||||
delegationFedPort,
|
||||
delegationClientPort,
|
||||
fedPort,
|
||||
clientPort,
|
||||
serverName,
|
||||
synapseServerName,
|
||||
}) => `_matrix._tcp.${serverName} 3600 IN SRV 10 5 ${delegationClientPort} ${synapseServerName}`
|
||||
@@ -0,0 +1,6 @@
|
||||
export default ({
|
||||
synapseServerName,
|
||||
delegationSynapsePort,
|
||||
}) => `{
|
||||
"m.server": "${synapseServerName}:${delegationSynapsePort}"
|
||||
}`
|
||||
51
synapse_topology/webui/src/js/templates/haproxy.js
Normal file
51
synapse_topology/webui/src/js/templates/haproxy.js
Normal file
@@ -0,0 +1,51 @@
|
||||
/* eslint-disable max-len */
|
||||
export default ({
|
||||
delegationFedPort,
|
||||
delegationClientPort,
|
||||
fedPort,
|
||||
clientPort,
|
||||
synapseServerName,
|
||||
}) => {
|
||||
|
||||
if (fedPort == clientPort) {
|
||||
|
||||
return `frontend https
|
||||
bind :::${delegationClientPort} v4v6 ssl crt /etc/ssl/haproxy/ strict-sni alpn h2,http/1.1
|
||||
|
||||
# Matrix client traffic
|
||||
acl matrix-host hdr(host) -i ${synapseServerName}
|
||||
acl matrix-path path_beg /_matrix
|
||||
|
||||
use_backend matrix if matrix-host matrix-path
|
||||
|
||||
frontend matrix-federation
|
||||
bind :::${delegationFedPort} v4v6 ssl crt /etc/ssl/haproxy/<your_tls_cert>.pem alpn h2,http/1.1
|
||||
default_backend matrix
|
||||
|
||||
backend matrix
|
||||
server matrix 127.0.0.1:${fedPort}
|
||||
`
|
||||
|
||||
} else {
|
||||
|
||||
return `frontend https
|
||||
bind:::${delegationClientPort} v4v6 ssl crt /etc/ssl/haproxy/ strict-sni alpn h2, http / 1.1
|
||||
|
||||
# Matrix client traffic
|
||||
acl matrix-host hdr(host) -i ${synapseServerName}
|
||||
acl matrix-path path_beg /_matrix
|
||||
|
||||
use_backend matrix-client if matrix-host matrix-path
|
||||
|
||||
frontend matrix - federation
|
||||
bind::: ${delegationFedPort} v4v6 ssl crt /etc/ssl/haproxy/<your_tls_cert>.pem alpn h2,http/1.1
|
||||
default_backend matrix
|
||||
|
||||
backend matrix
|
||||
server matrix 127.0.0.1:${fedPort}
|
||||
|
||||
backend matrix-client 127.0.0.1:${clientPort}`
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
27
synapse_topology/webui/src/js/templates/nginx.js
Normal file
27
synapse_topology/webui/src/js/templates/nginx.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import React from 'react';
|
||||
export default ({
|
||||
delegationFedPort,
|
||||
delegationClientPort,
|
||||
fedPort,
|
||||
clientPort,
|
||||
synapseServerName,
|
||||
}) => `listen {delegationClientPort} ssl;
|
||||
listen [::]:${delegationClientPort} ssl;
|
||||
server_name ${synapseServerName};
|
||||
|
||||
location /_matrix {
|
||||
proxy_pass http://localhost:${clientPort};
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen ${delegationFedPort} ssl default_server;
|
||||
listen [::]:${delegationFedPort} ssl default_server;
|
||||
server_name ${synapseServerName};
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:${fedPort};
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
}
|
||||
}`
|
||||
154
synapse_topology/webui/src/js/utils/yaml.js
Normal file
154
synapse_topology/webui/src/js/utils/yaml.js
Normal file
@@ -0,0 +1,154 @@
|
||||
/* eslint-disable camelcase */
|
||||
import { TLS_TYPES, REVERSE_PROXY_TYPES, DATABASE_TYPES } from '../actions/constants';
|
||||
import { CONFIG_LOCK } from '../api/constants';
|
||||
|
||||
const listeners = config => {
|
||||
|
||||
const listeners = [];
|
||||
if (config.tls == TLS_TYPES.REVERSE_PROXY) {
|
||||
|
||||
listeners.push({
|
||||
port: config.synapseFederationPort,
|
||||
tls: false,
|
||||
bind_addresses: ['::1', '127.0.0.1'],
|
||||
type: "http",
|
||||
x_forwarded: true,
|
||||
|
||||
resources: [{
|
||||
names: ["federation"],
|
||||
compress: false,
|
||||
}],
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
listeners.push({
|
||||
port: config.synapseFederationPort,
|
||||
tls: true,
|
||||
type: "http",
|
||||
|
||||
resources: [{
|
||||
names: ["federation"],
|
||||
}],
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
if (config.synapseClientPort == config.synapseFederationPort) {
|
||||
|
||||
listeners[0].resources[0].names.push("client");
|
||||
|
||||
} else if (config.tls == TLS_TYPES.REVERSE_PROXY) {
|
||||
|
||||
listeners.push({
|
||||
port: config.synapseClientPort,
|
||||
tls: false,
|
||||
bind_addresses: ['::1', '127.0.0.1'],
|
||||
type: "http",
|
||||
x_forwarded: true,
|
||||
|
||||
resources: [{
|
||||
names: ["client"],
|
||||
compress: false,
|
||||
}],
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
listeners.push({
|
||||
port: config.synapseClientPort,
|
||||
tls: true,
|
||||
type: "http",
|
||||
|
||||
resources: [{
|
||||
names: ["client"],
|
||||
}],
|
||||
});
|
||||
|
||||
}
|
||||
return { listeners: listeners };
|
||||
|
||||
}
|
||||
|
||||
const tlsPaths = config => {
|
||||
|
||||
if (config.tls == TLS_TYPES.TLS) {
|
||||
|
||||
return {
|
||||
tls_certificate_path: config.tlsCertPath,
|
||||
tls_private_key_path: config.tlsCertKeyPath,
|
||||
}
|
||||
|
||||
} else if (config.tls == TLS_TYPES.ACME) {
|
||||
|
||||
return {
|
||||
tls_certificate_path:
|
||||
config.configDir + "/" + config.servername + ".tls.cert",
|
||||
tls_private_key_path:
|
||||
config.configDir + "/" + config.servername + ".tls.key",
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
return {}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const acme = config => {
|
||||
|
||||
if (config.tls == TLS_TYPES.ACME) {
|
||||
|
||||
return {
|
||||
acme_domain: config.delegationServerName ?
|
||||
config.delegationServerName :
|
||||
config.servername,
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
return {}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const database = config => {
|
||||
|
||||
if (config.databaseType == DATABASE_TYPES.SQLITE3) {
|
||||
return {
|
||||
database: {
|
||||
name: config.databaseType,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
database: {
|
||||
name: config.databaseType,
|
||||
args: {
|
||||
user: config.databaseUsername,
|
||||
password: config.databasePassword,
|
||||
host: config.databaseHost,
|
||||
database: config.database,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const baseConfigToSynapseConfig = config => {
|
||||
|
||||
const conf = {
|
||||
server_name: config.servername,
|
||||
report_stats: config.reportStats,
|
||||
...database(config),
|
||||
...listeners(config),
|
||||
...tlsPaths(config),
|
||||
...acme(config),
|
||||
[CONFIG_LOCK]: true,
|
||||
}
|
||||
console.log(conf)
|
||||
return conf
|
||||
|
||||
}
|
||||
38
synapse_topology/webui/src/scss/animations.scss
Normal file
38
synapse_topology/webui/src/scss/animations.scss
Normal file
@@ -0,0 +1,38 @@
|
||||
@mixin rippler {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
transform: translate3d(0, 0, 0);
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
background-image: radial-gradient(circle, #fff 10%, transparent 10.01%);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 50%;
|
||||
transform: scale(10, 10);
|
||||
opacity: 0;
|
||||
transition: transform .5s, opacity 1s;
|
||||
}
|
||||
|
||||
&:active:after {
|
||||
transform: scale(0, 0);
|
||||
opacity: .3;
|
||||
transition: 0s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@mixin dropshadowed {
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
|
||||
transition: all 0.3s cubic-bezier(.25,.8,.25,1);
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
|
||||
}
|
||||
}
|
||||
7
synapse_topology/webui/src/scss/bootstrap.min.css
vendored
Normal file
7
synapse_topology/webui/src/scss/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
243
synapse_topology/webui/src/scss/main.scss
Normal file
243
synapse_topology/webui/src/scss/main.scss
Normal file
@@ -0,0 +1,243 @@
|
||||
@import './themes.scss';
|
||||
@import './animations.scss';
|
||||
@import './bootstrap.min.css';
|
||||
@mixin theme {
|
||||
@include dark;
|
||||
}
|
||||
|
||||
// Type selectors (Parents)
|
||||
|
||||
html {
|
||||
box-sizing: border-box;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
*, *:before, *:after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
body {
|
||||
@include theme;
|
||||
background-color: $primary;
|
||||
color: $font;
|
||||
margin: auto;
|
||||
width: 48rem;
|
||||
max-width: 90%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
// Type selectors (Children)
|
||||
|
||||
a {
|
||||
@include theme;
|
||||
color: $link;
|
||||
text-decoration: none;
|
||||
font-size: 0.6rem;
|
||||
line-height: 0.8rem;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: $link;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
button {
|
||||
@include rippler;
|
||||
border-radius: 5rem;
|
||||
font-size: 0.8rem;
|
||||
padding: 0.4rem 1.2rem;
|
||||
color: $font;
|
||||
background-color: $tertiary;
|
||||
border: none;
|
||||
display: inline-block;
|
||||
text-transform: capitalize;
|
||||
font-style: bold;
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: $link;
|
||||
}
|
||||
|
||||
|
||||
button[disabled] {
|
||||
background-color: darken($secondary, 8%);
|
||||
color: lighten($font, 50%);
|
||||
}
|
||||
|
||||
h1 {
|
||||
@include theme;
|
||||
font-size: 1rem;
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
input {
|
||||
padding: 0.4rem;
|
||||
font-size: 0.6rem;
|
||||
border-style: none;
|
||||
background: white;
|
||||
border-radius: 4rem;
|
||||
color: $font;
|
||||
padding: 0.4rem 1.2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
input[type=checkbox] {
|
||||
margin-right: 0.4rem;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 0.6rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 0.6rem;
|
||||
line-height: 0.8rem;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: white;
|
||||
border-radius: 0.4rem;
|
||||
color: $font;
|
||||
padding: 1rem;
|
||||
font-size: 0.6rem;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
select {
|
||||
font-size: 0.7rem;
|
||||
margin-bottom: 1.3rem;
|
||||
|
||||
&:after {
|
||||
content: ▸;
|
||||
transform: rotate(90deg);
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Class selectors
|
||||
|
||||
.active-card-header {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.baseintro {
|
||||
padding: 2rem 1rem;
|
||||
}
|
||||
|
||||
.blockwrapper {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.buttonDisplay {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-evenly;
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.buttonGroup {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
text-align: left;
|
||||
border-style: none;
|
||||
background: $secondary;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
font-size: 0.8rem;
|
||||
border-style: none;
|
||||
}
|
||||
|
||||
.card-header-tabs {
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.chevron {
|
||||
float:right;
|
||||
}
|
||||
|
||||
.inactive-card-header {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.inputButton {
|
||||
margin-left: 0.6rem;
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
|
||||
.inlineError {
|
||||
color: $error;
|
||||
font-size: 0.6rem;
|
||||
line-height: 0.8rem;
|
||||
span {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.invalid {
|
||||
border-color: $error;
|
||||
}
|
||||
|
||||
.invalidInput {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.keyDisplay {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.logo {
|
||||
position: absolute;
|
||||
top:0;
|
||||
right: 0;
|
||||
margin: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-link.active {
|
||||
border-color: transparent;
|
||||
background-color: $smoke;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-link:hover {
|
||||
border-color: transparent;
|
||||
background-color: $smoke;
|
||||
}
|
||||
|
||||
.or {
|
||||
font-size: 0.6rem;
|
||||
margin-left: 0.4rem;
|
||||
margin-right: 0.4rem;
|
||||
}
|
||||
|
||||
.redButton {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.servername {
|
||||
position: absolute;
|
||||
margin-top: 0.5rem;
|
||||
margin-left: 0.5rem;
|
||||
color: darken(silver, 20%);
|
||||
}
|
||||
|
||||
.setupCompleteTitle {
|
||||
margin-left: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
background-color: $smoke;
|
||||
padding: 1rem;
|
||||
}
|
||||
10
synapse_topology/webui/src/scss/themes.scss
Normal file
10
synapse_topology/webui/src/scss/themes.scss
Normal file
@@ -0,0 +1,10 @@
|
||||
@mixin dark {
|
||||
$primary: #ffffff !global;
|
||||
$secondary: #f4f4f4 !global;
|
||||
$tertiary: #3b444b !global;
|
||||
$smoke: #ececec !global;
|
||||
$font: #333 !global;
|
||||
$highlight: #4aeff0 !global;
|
||||
$link: #0098d4 !global;
|
||||
$error: #e32017 !global;
|
||||
}
|
||||
73
synapse_topology/webui/webpack.config.babel.js
Normal file
73
synapse_topology/webui/webpack.config.babel.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import 'webpack';
|
||||
import path from 'path';
|
||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||
import HtmlWebpackTagsPlugin from 'html-webpack-tags-plugin';
|
||||
|
||||
export default {
|
||||
entry: ['./src/js/index.jsx', './src/scss/main.scss', './src/scss/bootstrap.min.css'],
|
||||
watch: true,
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: 'bundle.js',
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.jsx', '.css'],
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.jsx$/,
|
||||
exclude: /node_modules/,
|
||||
use: ['babel-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'style-loader',
|
||||
},
|
||||
{
|
||||
loader: 'css-loader',
|
||||
},
|
||||
{
|
||||
loader: 'sass-loader',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: 'css/[name].css',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]',
|
||||
outputPath: 'fonts/',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
hash: true,
|
||||
filename: __dirname + '/dist/index.html',
|
||||
title: 'Topology - The synapse configuration tool',
|
||||
}),
|
||||
new HtmlWebpackTagsPlugin({
|
||||
tags: ['css/bootstrap.min.css'],
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user