def parse_config(config: dict):
        """Check that the configuration includes the required keys and parse the values
        expressed as durations."""
        if "period" not in config:
            raise ConfigError(
                "'period' is required when using email account validity")

        if "renew_at" not in config:
            raise ConfigError(
                "'renew_at' is required when using email account validity")

        config["period"] = Config.parse_duration(config.get("period") or 0)
        config["renew_at"] = Config.parse_duration(config.get("renew_at") or 0)
        return config
    def parse_config(config):
        """Called on startup to parse config supplied. This should parse
        the config and raise if there is a problem.

        The returned value is passed into the constructor.

        In this case we only care about a single param, the directory, so let's
        just pull that out.
        """
        return Config.ensure_directory(config["directory"])
Example #3
0
    def parse_config(config):
        """Called on startup to parse config supplied. This should parse
        the config and raise if there is a problem.

        The returned value is passed into the constructor.

        In this case we only care about a single param, the directory, so let's
        just pull that out.
        """
        return Config.ensure_directory(config["directory"])
Example #4
0
    def __init__(self, config: dict, api: ModuleApi):
        self._api = api
        self._store = EmailAccountValidityStore(config, api)

        EmailAccountValidityBase.__init__(self, config, self._api, self._store)
        DirectServeHtmlResource.__init__(self)

        if "period" in config:
            self._period = Config.parse_duration(config["period"])
        else:
            raise ConfigError(
                "'period' is required when using account validity")

        (
            self._account_renewed_template,
            self._account_previously_renewed_template,
            self._invalid_token_template,
        ) = api.read_templates([
            "account_renewed.html",
            "account_previously_renewed.html",
            "invalid_token.html",
        ])
Example #5
0
def main() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-c",
        "--config-path",
        action="append",
        metavar="CONFIG_FILE",
        help="The config files for Synapse.",
        required=True,
    )
    parser.add_argument(
        "-s",
        "--since",
        metavar="duration",
        help=
        "Specify how far back to review user registrations for, defaults to 7d (i.e. 7 days).",
        default="7d",
    )
    parser.add_argument(
        "-e",
        "--exclude-emails",
        action="store_true",
        help="Exclude users that have validated email addresses.",
    )
    parser.add_argument(
        "-u",
        "--only-users",
        action="store_true",
        help="Only print user IDs that match.",
    )
    parser.add_argument(
        "-a",
        "--exclude-app-service",
        help="Exclude appservice users.",
        action="store_true",
    )

    config = ReviewConfig()

    config_args = parser.parse_args(sys.argv[1:])
    config_files = find_config_files(search_paths=config_args.config_path)
    config_dict = read_config_files(config_files)
    config.parse_config_dict(config_dict, "", "")

    since_ms = time.time() * 1000 - Config.parse_duration(config_args.since)
    exclude_users_with_email = config_args.exclude_emails
    exclude_users_with_appservice = config_args.exclude_app_service
    include_context = not config_args.only_users

    for database_config in config.database.databases:
        if "main" in database_config.databases:
            break

    engine = create_engine(database_config.config)

    with make_conn(database_config, engine,
                   "review_recent_signups") as db_conn:
        # This generates a type of Cursor, not LoggingTransaction.
        user_infos = get_recent_users(
            db_conn.cursor(), since_ms,
            exclude_users_with_appservice)  # type: ignore[arg-type]

    for user_info in user_infos:
        if exclude_users_with_email and user_info.emails:
            continue

        if include_context:
            print_public_rooms = ""
            if user_info.public_rooms:
                print_public_rooms = "(" + ", ".join(
                    user_info.public_rooms[:3])

                if len(user_info.public_rooms) > 3:
                    print_public_rooms += ", ..."

                print_public_rooms += ")"

            print("# Created:", datetime.fromtimestamp(user_info.creation_ts))
            print("# Email:", ", ".join(user_info.emails) or "None")
            print("# IPs:", ", ".join(user_info.ips))
            print(
                "# Number joined public rooms:",
                len(user_info.public_rooms),
                print_public_rooms,
            )
            print("# Number joined private rooms:",
                  len(user_info.private_rooms))
            print("#")

        print(user_info.user_id)

        if include_context:
            print()
Example #6
0
 def parse_config(config: dict) -> dict:
     config["period"] = Config.parse_duration(config.get("period") or 0)
     return config
Example #7
0
 def setUp(self):
     # The root object needs a server property with a public_baseurl.
     root = Mock()
     root.server.public_baseurl = "http://test"
     self.config = Config(root)
Example #8
0
class BaseConfigTestCase(unittest.TestCase):
    def setUp(self):
        # The root object needs a server property with a public_baseurl.
        root = Mock()
        root.server.public_baseurl = "http://test"
        self.config = Config(root)

    def test_loading_missing_templates(self):
        # Use a temporary directory that exists on the system, but that isn't likely to
        # contain template files
        with tempfile.TemporaryDirectory() as tmp_dir:
            # Attempt to load an HTML template from our custom template directory
            template = self.config.read_templates(["sso_error.html"],
                                                  (tmp_dir, ))[0]

        # If no errors, we should've gotten the default template instead

        # Render the template
        a_random_string = random_string(5)
        html_content = template.render({"error_description": a_random_string})

        # Check that our string exists in the template
        self.assertIn(
            a_random_string,
            html_content,
            "Template file did not contain our test string",
        )

    def test_loading_custom_templates(self):
        # Use a temporary directory that exists on the system
        with tempfile.TemporaryDirectory() as tmp_dir:
            # Create a temporary bogus template file
            with tempfile.NamedTemporaryFile(dir=tmp_dir) as tmp_template:
                # Get temporary file's filename
                template_filename = os.path.basename(tmp_template.name)

                # Write a custom HTML template
                contents = b"{{ test_variable }}"
                tmp_template.write(contents)
                tmp_template.flush()

                # Attempt to load the template from our custom template directory
                template = (self.config.read_templates([template_filename],
                                                       (tmp_dir, )))[0]

        # Render the template
        a_random_string = random_string(5)
        html_content = template.render({"test_variable": a_random_string})

        # Check that our string exists in the template
        self.assertIn(
            a_random_string,
            html_content,
            "Template file did not contain our test string",
        )

    def test_multiple_custom_template_directories(self):
        """Tests that directories are searched in the right order if multiple custom
        template directories are provided.
        """
        # Create two temporary directories on the filesystem.
        tempdirs = [
            tempfile.TemporaryDirectory(),
            tempfile.TemporaryDirectory(),
        ]

        # Create one template in each directory, whose content is the index of the
        # directory in the list.
        template_filename = "my_template.html.j2"
        for i in range(len(tempdirs)):
            tempdir = tempdirs[i]
            template_path = os.path.join(tempdir.name, template_filename)

            with open(template_path, "w") as fp:
                fp.write(str(i))
                fp.flush()

        # Retrieve the template.
        template = (self.config.read_templates(
            [template_filename],
            (td.name for td in tempdirs),
        ))[0]

        # Test that we got the template we dropped in the first directory in the list.
        self.assertEqual(template.render(), "0")

        # Add another template, this one only in the second directory in the list, so we
        # can test that the second directory is still searched into when no matching file
        # could be found in the first one.
        other_template_name = "my_other_template.html.j2"
        other_template_path = os.path.join(tempdirs[1].name,
                                           other_template_name)

        with open(other_template_path, "w") as fp:
            fp.write("hello world")
            fp.flush()

        # Retrieve the template.
        template = (self.config.read_templates(
            [other_template_name],
            (td.name for td in tempdirs),
        ))[0]

        # Test that the file has the expected content.
        self.assertEqual(template.render(), "hello world")

        # Cleanup the temporary directories manually since we're not using a context
        # manager.
        for td in tempdirs:
            td.cleanup()

    def test_loading_template_from_nonexistent_custom_directory(self):
        with self.assertRaises(ConfigError):
            self.config.read_templates(["some_filename.html"],
                                       ("a_nonexistent_directory", ))