diff --git a/electron_app/riot.im/README b/electron_app/riot.im/README index 09c218740c..8e463c25ec 100644 --- a/electron_app/riot.im/README +++ b/electron_app/riot.im/README @@ -1,4 +1,6 @@ This directory contains the config file for the official riot.im distribution -of Riot Desktop. You probably do not want to build with this config unless -you're building the official riot.im distribution, or you'll find your builds -will replace themselves with the riot.im build. +of Riot Desktop. + +You probably do not want to build with this config unless you're building the +official riot.im distribution, or you'll find your builds will replace +themselves with the riot.im build. diff --git a/riot.im/README b/riot.im/README new file mode 100644 index 0000000000..2186e48dee --- /dev/null +++ b/riot.im/README @@ -0,0 +1,11 @@ +This directory contains the config files and deployment scripts for the official +riot.im distribution of Riot Web at https://riot.im. + +You probably do not want to build with this config unless you're building the +official riot.im distribution, but these files may be useful if you want to +inspect the configuration used there. + +Riot Desktop uses a separate config (see electron_app/riot.im/config.json). + +Deployment scripts (such as app/deploy.py) are meant to be run on the web server +hosting the Riot installation. diff --git a/riot.im/app/config.json b/riot.im/app/config.json new file mode 100644 index 0000000000..fc67720530 --- /dev/null +++ b/riot.im/app/config.json @@ -0,0 +1,48 @@ +{ + "default_hs_url": "https://matrix.org", + "default_is_url": "https://vector.im", + "brand": "Riot", + "integrations_ui_url": "https://scalar.vector.im/", + "integrations_rest_url": "https://scalar.vector.im/api", + "integrations_widgets_urls": [ + "https://scalar-staging.vector.im/api", + "https://scalar.vector.im/api", + "https://scalar-staging.riot.im/scalar/api" + ], + "hosting_signup_link": "https://modular.im/?utm_source=riot-web&utm_medium=web", + "bug_report_endpoint_url": "https://riot.im/bugreports/submit", + "welcomeUserId": "@riot-bot:matrix.org", + "piwik": { + "url": "https://piwik.riot.im/", + "siteId": 1, + "policyUrl": "https://matrix.org/docs/guides/riot_im_cookie_policy" + }, + "phasedRollOut": { + "feature_lazyloading": { + "offset": 1539684000000, + "period": 604800000 + } + }, + "features": { + "feature_lazyloading": "enable", + "feature_room_breadcrumbs": "labs" + }, + "roomDirectory": { + "servers": [ + "matrix.org" + ] + }, + "enable_presence_by_hs_url": { + "https://matrix.org": false + }, + "terms_and_conditions_links": [ + { + "url": "https://riot.im/privacy", + "text": "Privacy Policy" + }, + { + "url": "https://matrix.org/docs/guides/riot_im_cookie_policy", + "text": "Cookie Policy" + } + ] +} diff --git a/riot.im/app/deploy.py b/riot.im/app/deploy.py new file mode 100755 index 0000000000..33aa0af017 --- /dev/null +++ b/riot.im/app/deploy.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python +# +# download and unpack a riot-web tarball. +# +# Allows `bundles` to be extracted to a common directory, and a link to +# config.json to be added. + +from __future__ import print_function + +import argparse +import os +import os.path +import subprocess +import sys +import tarfile +import shutil +import glob + +try: + # python3 + from urllib.request import urlretrieve +except ImportError: + # python2 + from urllib import urlretrieve + +class DeployException(Exception): + pass + +def create_relative_symlink(linkname, target): + relpath = os.path.relpath(target, os.path.dirname(linkname)) + print ("Symlink %s -> %s" % (linkname, relpath)) + os.symlink(relpath, linkname) + + +def move_bundles(source, dest): + """Move the contents of the 'bundles' directory to a common dir + + We check that we will not be overwriting anything before we proceed. + + Args: + source (str): path to 'bundles' within the extracted tarball + dest (str): target common directory + """ + + if not os.path.isdir(dest): + os.mkdir(dest) + + # build a map from source to destination, checking for non-existence as we go. + renames = {} + for f in os.listdir(source): + dst = os.path.join(dest, f) + if os.path.exists(dst): + print ( + "Skipping bundle. The bundle includes '%s' which we have previously deployed." + % f + ) + else: + renames[os.path.join(source, f)] = dst + + for (src, dst) in renames.iteritems(): + print ("Move %s -> %s" % (src, dst)) + os.rename(src, dst) + +class Deployer: + def __init__(self): + self.packages_path = "." + self.bundles_path = None + self.should_clean = False + # filename -> symlink path e.g 'config.localhost.json' => '../localhost/config.json' + self.symlink_paths = {} + self.verify_signature = True + + def deploy(self, tarball, extract_path): + """Download a tarball if necessary, and unpack it + + Returns: + (str) the path to the unpacked deployment + """ + print("Deploying %s to %s" % (tarball, extract_path)) + + name_str = os.path.basename(tarball).replace(".tar.gz", "") + extracted_dir = os.path.join(extract_path, name_str) + if os.path.exists(extracted_dir): + raise DeployException('Cannot unpack %s: %s already exists' % ( + tarball, extracted_dir)) + + downloaded = False + if tarball.startswith("http://") or tarball.startswith("https://"): + tarball = self.download_and_verify(tarball) + print("Downloaded file: %s" % tarball) + downloaded = True + + try: + with tarfile.open(tarball) as tar: + tar.extractall(extract_path) + finally: + if self.should_clean and downloaded: + os.remove(tarball) + + print ("Extracted into: %s" % extracted_dir) + + if self.symlink_paths: + for link_path, file_path in self.symlink_paths.iteritems(): + create_relative_symlink( + target=file_path, + linkname=os.path.join(extracted_dir, link_path) + ) + + if self.bundles_path: + extracted_bundles = os.path.join(extracted_dir, 'bundles') + move_bundles(source=extracted_bundles, dest=self.bundles_path) + + # replace the extracted_bundles dir (which may not be empty if some + # bundles were skipped) with a symlink to the common dir. + shutil.rmtree(extracted_bundles) + create_relative_symlink( + target=self.bundles_path, + linkname=extracted_bundles, + ) + return extracted_dir + + def download_and_verify(self, url): + tarball = self.download_file(url) + + if self.verify_signature: + sigfile = self.download_file(url + ".asc") + subprocess.check_call(["gpg", "--verify", sigfile, tarball]) + + return tarball + + def download_file(self, url): + if not os.path.isdir(self.packages_path): + os.mkdir(self.packages_path) + local_filename = os.path.join(self.packages_path, + url.split('/')[-1]) + sys.stdout.write("Downloading %s -> %s..." % (url, local_filename)) + sys.stdout.flush() + urlretrieve(url, local_filename) + print ("Done") + return local_filename + +if __name__ == "__main__": + parser = argparse.ArgumentParser("Deploy a Riot build on a web server.") + parser.add_argument( + "-p", "--packages-dir", default="./packages", help=( + "The directory to download the tarball into. (Default: '%(default)s')" + ) + ) + parser.add_argument( + "-e", "--extract-path", default="./deploys", help=( + "The location to extract .tar.gz files to. (Default: '%(default)s')" + ) + ) + parser.add_argument( + "-b", "--bundles-dir", nargs='?', default="./bundles", help=( + "A directory to move the contents of the 'bundles' directory to. A \ + symlink to the bundles directory will also be written inside the \ + extracted tarball. Example: './bundles'. \ + (Default: '%(default)s')" + ) + ) + parser.add_argument( + "-c", "--clean", action="store_true", default=False, help=( + "Remove .tar.gz files after they have been downloaded and extracted. \ + (Default: %(default)s)" + ) + ) + parser.add_argument( + "--include", nargs='*', default=['./config*.json'], help=( + "Symlink these files into the root of the deployed tarball. \ + Useful for config files and home pages. Supports glob syntax. \ + (Default: '%(default)s')" + ) + ) + parser.add_argument( + "tarball", help=( + "filename of tarball, or URL to download." + ), + ) + + args = parser.parse_args() + + deployer = Deployer() + deployer.packages_path = args.packages_dir + deployer.bundles_path = args.bundles_dir + deployer.should_clean = args.clean + + for include in args.include: + deployer.symlink_paths.update({ os.path.basename(pth): pth for pth in glob.iglob(include) }) + + deployer.deploy(args.tarball, args.extract_path) diff --git a/riot.im/develop/config.json b/riot.im/develop/config.json new file mode 100644 index 0000000000..b687235c3c --- /dev/null +++ b/riot.im/develop/config.json @@ -0,0 +1,56 @@ +{ + "default_hs_url": "https://matrix.org", + "default_is_url": "https://vector.im", + "brand": "Riot", + "integrations_ui_url": "https://scalar-staging.vector.im/", + "integrations_rest_url": "https://scalar-staging.vector.im/api", + "integrations_widgets_urls": [ + "https://scalar-staging.riot.im/scalar/api", + "https://scalar-staging.vector.im/api", + "https://scalar.vector.im/api" + ], + "hosting_signup_link": "https://modular.im/?utm_source=riot-web&utm_medium=web", + "bug_report_endpoint_url": "https://riot.im/bugreports/submit", + "features": { + "feature_rich_quoting": "labs", + "feature_pinning": "labs", + "feature_presence_management": "labs", + "feature_sticker_messages": "labs", + "feature_jitsi": "labs", + "feature_tag_panel": "enable", + "feature_keybackup": "labs", + "feature_custom_status": "labs", + "feature_custom_tags": "labs", + "feature_lazyloading": "enable", + "feature_tabbed_settings": "labs", + "feature_sas": "labs", + "feature_room_breadcrumbs": "labs", + "feature_state_counters": "labs", + "feature_reactions": "enable", + "feature_message_editing": "enable" + }, + "welcomeUserId": "@riot-bot:matrix.org", + "piwik": { + "url": "https://piwik.riot.im/", + "siteId": 1, + "policyUrl": "https://matrix.org/docs/guides/riot_im_cookie_policy" + }, + "roomDirectory": { + "servers": [ + "matrix.org" + ] + }, + "enable_presence_by_hs_url": { + "https://matrix.org": false + }, + "terms_and_conditions_links": [ + { + "url": "https://riot.im/privacy", + "text": "Privacy Policy" + }, + { + "url": "https://matrix.org/docs/guides/riot_im_cookie_policy", + "text": "Cookie Policy" + } + ] +}