From 076ffa9cf0732de37e92c4dfbe8c0eb1a5169cbe Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Sun, 10 Oct 2021 12:00:00 +0000 Subject: [PATCH 1/3] python3Packages.flask-talisman: init at 0.8.1 --- .../python-modules/flask-talisman/default.nix | 36 +++++++++++++++++++ pkgs/top-level/python-packages.nix | 2 ++ 2 files changed, 38 insertions(+) create mode 100644 pkgs/development/python-modules/flask-talisman/default.nix diff --git a/pkgs/development/python-modules/flask-talisman/default.nix b/pkgs/development/python-modules/flask-talisman/default.nix new file mode 100644 index 000000000000..b57d58824705 --- /dev/null +++ b/pkgs/development/python-modules/flask-talisman/default.nix @@ -0,0 +1,36 @@ +{ lib +, buildPythonPackage +, fetchPypi +, flask +, six +, pytestCheckHook +}: + +buildPythonPackage rec { + pname = "flask-talisman"; + version = "0.8.1"; + + src = fetchPypi { + inherit pname version; + sha256 = "11gjgqkpj2yqydb0pfhjyx56iy4l9szgz33vg5d7bw8vqp02wl2x"; + }; + + buildInputs = [ + flask + ]; + + propagatedBuildInputs = [ + six + ]; + + nativeBuildInputs = [ + pytestCheckHook + ]; + + meta = with lib; { + description = "HTTP security headers for Flask"; + homepage = "https://github.com/wntrblm/flask-talisman"; + license = licenses.asl20; + maintainers = [ lib.maintainers.symphorien ]; + }; +} diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix index 7b422e43f20c..0af977c367eb 100644 --- a/pkgs/top-level/python-packages.nix +++ b/pkgs/top-level/python-packages.nix @@ -2755,6 +2755,8 @@ in { flask-swagger-ui = callPackage ../development/python-modules/flask-swagger-ui { }; + flask-talisman = callPackage ../development/python-modules/flask-talisman { }; + flask_testing = callPackage ../development/python-modules/flask-testing { }; flask-versioned = callPackage ../development/python-modules/flask-versioned { }; From e28414b63dd4161e3d8f32a6779fe2df52091302 Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Sun, 10 Oct 2021 12:00:00 +0000 Subject: [PATCH 2/3] python3.pkgs.ihatemoney: 4.2 -> 5.1.1 --- .../services/web-apps/ihatemoney/default.nix | 18 +- nixos/tests/all-tests.nix | 2 +- .../default.nix} | 32 +- nixos/tests/ihatemoney/rates.json | 39 +++ nixos/tests/ihatemoney/server.crt | 28 ++ nixos/tests/ihatemoney/server.key | 52 ++++ .../python-modules/ihatemoney/default.nix | 57 +--- .../ihatemoney/remove_flask_script.patch | 284 ------------------ 8 files changed, 173 insertions(+), 339 deletions(-) rename nixos/tests/{ihatemoney.nix => ihatemoney/default.nix} (52%) create mode 100644 nixos/tests/ihatemoney/rates.json create mode 100644 nixos/tests/ihatemoney/server.crt create mode 100644 nixos/tests/ihatemoney/server.key delete mode 100644 pkgs/development/python-modules/ihatemoney/remove_flask_script.patch diff --git a/nixos/modules/services/web-apps/ihatemoney/default.nix b/nixos/modules/services/web-apps/ihatemoney/default.nix index b4987fa4702c..238241854c1c 100644 --- a/nixos/modules/services/web-apps/ihatemoney/default.nix +++ b/nixos/modules/services/web-apps/ihatemoney/default.nix @@ -33,11 +33,14 @@ let then "sqlite:////var/lib/ihatemoney/ihatemoney.sqlite" else "postgresql:///${db}"}' SQLALCHEMY_TRACK_MODIFICATIONS = False - MAIL_DEFAULT_SENDER = ("${cfg.defaultSender.name}", "${cfg.defaultSender.email}") + MAIL_DEFAULT_SENDER = (r"${cfg.defaultSender.name}", r"${cfg.defaultSender.email}") ACTIVATE_DEMO_PROJECT = ${toBool cfg.enableDemoProject} - ADMIN_PASSWORD = "${toString cfg.adminHashedPassword /*toString null == ""*/}" + ADMIN_PASSWORD = r"${toString cfg.adminHashedPassword /*toString null == ""*/}" ALLOW_PUBLIC_PROJECT_CREATION = ${toBool cfg.enablePublicProjectCreation} ACTIVATE_ADMIN_DASHBOARD = ${toBool cfg.enableAdminDashboard} + SESSION_COOKIE_SECURE = ${toBool cfg.secureCookie} + ENABLE_CAPTCHA = ${toBool cfg.enableCaptcha} + LEGAL_LINK = r"${toString cfg.legalLink}" ${cfg.extraConfig} ''; @@ -79,9 +82,20 @@ in description = "The email of the sender of ihatemoney emails"; }; }; + secureCookie = mkOption { + type = types.bool; + default = true; + description = "Use secure cookies. Disable this when ihatemoney is served via http instead of https"; + }; enableDemoProject = mkEnableOption "access to the demo project in ihatemoney"; enablePublicProjectCreation = mkEnableOption "permission to create projects in ihatemoney by anyone"; enableAdminDashboard = mkEnableOption "ihatemoney admin dashboard"; + enableCaptcha = mkEnableOption "a simplistic captcha for some forms"; + legalLink = mkOption { + type = types.nullOr types.str; + default = null; + description = "The URL to a page explaining legal statements about your service, eg. GDPR-related information."; + }; extraConfig = mkOption { type = types.str; default = ""; diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index a6eb2c032588..73ca14bd5393 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -190,7 +190,7 @@ in i3wm = handleTest ./i3wm.nix {}; icingaweb2 = handleTest ./icingaweb2.nix {}; iftop = handleTest ./iftop.nix {}; - ihatemoney = handleTest ./ihatemoney.nix {}; + ihatemoney = handleTest ./ihatemoney {}; incron = handleTest ./incron.nix {}; influxdb = handleTest ./influxdb.nix {}; initrd-network-openvpn = handleTest ./initrd-network-openvpn {}; diff --git a/nixos/tests/ihatemoney.nix b/nixos/tests/ihatemoney/default.nix similarity index 52% rename from nixos/tests/ihatemoney.nix rename to nixos/tests/ihatemoney/default.nix index 0451a4505808..78278d2e8699 100644 --- a/nixos/tests/ihatemoney.nix +++ b/nixos/tests/ihatemoney/default.nix @@ -1,22 +1,36 @@ { system ? builtins.currentSystem, config ? {}, - pkgs ? import ../.. { inherit system config; } + pkgs ? import ../../.. { inherit system config; } }: let - inherit (import ../lib/testing-python.nix { inherit system pkgs; }) makeTest; + inherit (import ../../lib/testing-python.nix { inherit system pkgs; }) makeTest; f = backend: makeTest { name = "ihatemoney-${backend}"; - machine = { lib, ... }: { + machine = { nodes, lib, ... }: { services.ihatemoney = { enable = true; enablePublicProjectCreation = true; + secureCookie = false; inherit backend; uwsgiConfig = { http = ":8000"; }; }; boot.cleanTmpDir = true; + # for exchange rates + security.pki.certificateFiles = [ ./server.crt ]; + networking.extraHosts = "127.0.0.1 api.exchangerate.host"; + services.nginx = { + enable = true; + virtualHosts."api.exchangerate.host" = { + addSSL = true; + # openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt -days 1000000 -nodes -subj '/CN=api.exchangerate.host' + sslCertificate = ./server.crt; + sslCertificateKey = ./server.key; + locations."/".return = "200 '${builtins.readFile ./rates.json}'"; + }; + }; # ihatemoney needs a local smtp server otherwise project creation just crashes services.opensmtpd = { enable = true; @@ -30,11 +44,13 @@ let testScript = '' machine.wait_for_open_port(8000) machine.wait_for_unit("uwsgi.service") - machine.wait_until_succeeds("curl http://localhost:8000") + machine.wait_until_succeeds("curl --fail https://api.exchangerate.host") + machine.wait_until_succeeds("curl --fail http://localhost:8000") - assert '"yay"' in machine.succeed( - "curl -X POST http://localhost:8000/api/projects -d 'name=yay&id=yay&password=yay&contact_email=yay@example.com'" + result = machine.succeed( + "curl --fail -X POST http://localhost:8000/api/projects -d 'name=yay&id=yay&password=yay&contact_email=yay@example.com&default_currency=XXX'" ) + assert '"yay"' in result, repr(result) owner, timestamp = machine.succeed( "stat --printf %U:%G___%Y /var/lib/ihatemoney/secret_key" ).split("___") @@ -47,13 +63,13 @@ let machine.wait_for_unit("uwsgi.service") with subtest("check that the database is really persistent"): - machine.succeed("curl --basic -u yay:yay http://localhost:8000/api/projects/yay") + machine.succeed("curl --fail --basic -u yay:yay http://localhost:8000/api/projects/yay") with subtest("check that the secret key is really persistent"): timestamp2 = machine.succeed("stat --printf %Y /var/lib/ihatemoney/secret_key") assert timestamp == timestamp2 - assert "ihatemoney" in machine.succeed("curl http://localhost:8000") + assert "ihatemoney" in machine.succeed("curl --fail http://localhost:8000") ''; }; in { diff --git a/nixos/tests/ihatemoney/rates.json b/nixos/tests/ihatemoney/rates.json new file mode 100644 index 000000000000..ebdd2651b040 --- /dev/null +++ b/nixos/tests/ihatemoney/rates.json @@ -0,0 +1,39 @@ +{ + "rates": { + "CAD": 1.3420055134, + "HKD": 7.7513783598, + "ISK": 135.9407305307, + "PHP": 49.3762922123, + "DKK": 6.4126464507, + "HUF": 298.9145416954, + "CZK": 22.6292212267, + "GBP": 0.7838128877, + "RON": 4.1630771881, + "SEK": 8.8464851826, + "IDR": 14629.5658166782, + "INR": 74.8328738801, + "BRL": 5.2357856651, + "RUB": 71.8416609235, + "HRK": 6.4757064094, + "JPY": 106.2715368711, + "THB": 31.7203652653, + "CHF": 0.9243625086, + "EUR": 0.8614748449, + "MYR": 4.2644727774, + "BGN": 1.6848725017, + "TRY": 6.8483804273, + "CNY": 7.0169710544, + "NOK": 9.213731909, + "NZD": 1.5080978635, + "ZAR": 16.7427636113, + "USD": 1, + "MXN": 22.4676085458, + "SGD": 1.3855099931, + "AUD": 1.4107512061, + "ILS": 3.4150585803, + "KRW": 1203.3339076499, + "PLN": 3.794452102 + }, + "base": "USD", + "date": "2020-07-24" +} diff --git a/nixos/tests/ihatemoney/server.crt b/nixos/tests/ihatemoney/server.crt new file mode 100644 index 000000000000..10e568b14b14 --- /dev/null +++ b/nixos/tests/ihatemoney/server.crt @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIEvjCCAqYCCQDkTQrENPCZjjANBgkqhkiG9w0BAQsFADAgMR4wHAYDVQQDDBVh +cGkuZXhjaGFuZ2VyYXRlLmhvc3QwIBcNMjEwNzE0MTI1MzQ0WhgPNDc1OTA2MTEx +MjUzNDRaMCAxHjAcBgNVBAMMFWFwaS5leGNoYW5nZXJhdGUuaG9zdDCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAL5zpwUYa/ySqvJ/PUnXYsl1ww5SNGJh +NujCRxC0Gw+5t5O7USSHRdz7Eb2PNFMa7JR+lliLAWdjHfqPXJWmP10X5ebvyxeQ +TJkR1HpDSY6TQQlJvwr/JNGryyoQYjXvnyeyVu4TS3U0TTI631OonDAj+HbFIs9L +gr/HfHzFmxRVLwaJ7hebanihc5RzoWTxgswiOwYQu5AivXQqcvUIxELeT7CxWwiw +be/SlalDgoezB/poqaa215FUuN2av+nTn+swH3WOi9kwePLgVKn9BnDMwyh8et13 +yt27RWCSOcZagRSYsSbBaEJbClZvnuYvDqooJEy0GVbGBZpClKRKe92yd0PTf3ZJ +GupyNoCFQlGugY//WLrsPv/Q4WwP+qZ6t97sV0CdM+epKVde/LfPKn+tFMv86qIg +Q/uGHdDwUI8XH2EysAavhdlssSrovmpl4hyo9UkzTWfJgAbmOZY3Vba41wsq12FT +usDsswGLBD10MdXWltR/Hdk8OnosLmeJxfZODAv31KSfd+4b6Ntr9BYQvAQSO+1/ +Mf7gEQtNhO003VKIyV5cpH4kVQieEcvoEKgq32NVBSKVf6UIPWIefu19kvrttaUu +Q2QW2Qm4Ph/4cWpxl0jcrN5rjmgaBtIMmKYjRIS0ThDWzfVkJdmJuATzExJAplLN +nYPBG3gOtQQpAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAJzt/aN7wl88WrvBasVi +fSJmJjRaW2rYyBUMptQNkm9ElHN2eQQxJgLi8+9ArQxuGKhHx+D1wMGF8w2yOp0j +4atfbXDcT+cTQY55qdEeYgU8KhESHHGszGsUpv7hzU2cACZiXG0YbOmORFYcn49Z +yPyN98kW8BViLzNF9v+I/NJPuaaCeWKjXCqY2GCzddiuotrlLtz0CODXZJ506I1F +38vQgZb10yAe6+R4y0BK7sUlmfr9BBqVcDQ/z74Kph1aB32zwP8KrNitwG1Tyk6W +rxD1dStEQyX8uDPAspe2JrToMWsOMje9F5lotmuzyvwRJYfAav300EtIggBqpiHR +o0P/1xxBzmaCHxEUJegdoYg8Q27llqsjR2T78uv/BlxpX9Dv5kNex5EZThKqyz4a +Fn1VqiA3D9IsvxH4ud+8eDaP24u1yYObSTDIBsw9xDvoV8fV+NWoNNhcAL5GwC0P +Goh7/brZSHUprxGpwRB524E//8XmCsRd/+ShtXbi4gEODMH4xLdkD7fZIJC4eG1H +GOVc1MwjiYvbQlPs6MOcQ0iKQneSlaEJmyyO5Ro5OKiKj89Az/mLYX3R17AIsu0T +Q5pGcmhKVRyu0zXvkGfK352TLwoe+4vbmakDq21Pkkcy8V9M4wP+vpCfQkg1REQ1 ++mr1Vg+SFya3mlCxpFTy3j8E +-----END CERTIFICATE----- diff --git a/nixos/tests/ihatemoney/server.key b/nixos/tests/ihatemoney/server.key new file mode 100644 index 000000000000..72a43577d64d --- /dev/null +++ b/nixos/tests/ihatemoney/server.key @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +NaEkKVO0D0jFtk37s/YqJpCsXg/B7yc= +-----END PRIVATE KEY----- diff --git a/pkgs/development/python-modules/ihatemoney/default.nix b/pkgs/development/python-modules/ihatemoney/default.nix index fc1cb34d32c6..5d768170d806 100644 --- a/pkgs/development/python-modules/ihatemoney/default.nix +++ b/pkgs/development/python-modules/ihatemoney/default.nix @@ -1,14 +1,13 @@ { buildPythonPackage , lib -, fetchFromGitHub , isPy27 , nixosTests -, fetchpatch , fetchPypi , alembic , aniso8601 , Babel , blinker +, cachetools , click , dnspython , email_validator @@ -19,6 +18,7 @@ , flask_migrate , flask-restful , flask_sqlalchemy +, flask-talisman , flask_wtf , debts , idna @@ -28,6 +28,7 @@ , markupsafe , python-dateutil , pytz +, requests , six , sqlalchemy , sqlalchemy-utils @@ -43,17 +44,6 @@ # ihatemoney is not really a library. It will only ever be imported # by the interpreter of uwsgi. So overrides for its depencies are fine. let - # fixed in next release, but patches don't apply - # https://github.com/spiral-project/ihatemoney/issues/567 - pinned_wtforms = wtforms.overridePythonAttrs (old: rec { - pname = "WTForms"; - version = "2.2.1"; - src = fetchPypi { - inherit pname version; - sha256 = "0q9vkcq6jnnn618h27lx9sas6s9qlg2mv8ja6dn0hy38gwzarnqc"; - }; - }); - # sqlalchemy-continuum requires sqlalchemy < 1.4 pinned_sqlalchemy = sqlalchemy.overridePythonAttrs ( old: rec { @@ -70,43 +60,20 @@ in buildPythonPackage rec { pname = "ihatemoney"; - version = "4.2"; + version = "5.1.1"; - src = fetchFromGitHub { - owner = "spiral-project"; - repo = pname; - rev = version; - sha256 = "0d4vc6m0jkwlz9ly0hcjghccydvqbldh2jb8yzf94jrgkd5fd7k1"; + src = fetchPypi { + inherit pname version; + sha256 = "0gsqba9qbs1dpmfys8qpiahy4pbn4khcc6mgmdnhssmkjsb94sx6"; }; disabled = isPy27; - patches = [ - # fix migration on postgresql - # remove on next release - (fetchpatch { - url = "https://github.com/spiral-project/ihatemoney/commit/6129191b26784b895e203fa3eafb89cee7d88b71.patch"; - sha256 = "0yc24gsih9x3pnh2mhj4v5i71x02dq93a9jd2r8b1limhcl4p1sw"; - }) - (fetchpatch { - name = "CVE-2020-15120.patch"; - url = "https://github.com/spiral-project/ihatemoney/commit/8d77cf5d5646e1d2d8ded13f0660638f57e98471.patch"; - sha256 = "0y855sk3qsbpq7slj876k2ifa1lccc2dccag98pkyaadpz5gbabv"; - }) - # backported from current master - # remove dependency on flask-script, which removed support on some features ihm used to need - ./remove_flask_script.patch - ]; - - postPatch = '' - # remove draconian pinning - sed -i 's/==.*$//' setup.cfg - ''; - propagatedBuildInputs = [ aniso8601 Babel blinker + cachetools click dnspython email_validator @@ -125,7 +92,8 @@ buildPythonPackage rec { } ) flask-restful - (flask_wtf.override { wtforms = pinned_wtforms; }) + flask-talisman + flask_wtf idna itsdangerous jinja2 @@ -133,6 +101,7 @@ buildPythonPackage rec { markupsafe python-dateutil pytz + requests six ( ( @@ -158,7 +127,7 @@ buildPythonPackage rec { ) ) werkzeug - pinned_wtforms + wtforms psycopg2 debts ]; @@ -168,10 +137,10 @@ buildPythonPackage rec { pytestCheckHook ]; - pytestFlagsArray = [ "--pyargs ihatemoney.tests.tests" ]; disabledTests = [ "test_notifications" # requires running service. "test_invite" # requires running service. + "test_invitation_email_failure" # requires dns resolution ]; passthru.tests = { diff --git a/pkgs/development/python-modules/ihatemoney/remove_flask_script.patch b/pkgs/development/python-modules/ihatemoney/remove_flask_script.patch deleted file mode 100644 index dac59680a09c..000000000000 --- a/pkgs/development/python-modules/ihatemoney/remove_flask_script.patch +++ /dev/null @@ -1,284 +0,0 @@ -commit 4d831ba2316d54f4916fb9d1160ec7a3856b47d4 -Author: Glandos -Date: Sun Jun 6 14:30:52 2021 +0200 - - remove usage of Flask-Script - - Use flask.cli instead with compatibility layer for existing commands, - such as "runserver". - - cherry-pick from 74e222f1a1cbfc2fac102fefc1115e9d0a6586dc - -diff --git a/Makefile b/Makefile -index a681709..90ab1bb 100644 ---- a/Makefile -+++ b/Makefile -@@ -38,7 +38,7 @@ update: remove-install-stamp install ## Update the dependencies - .PHONY: serve - serve: install ## Run the ihatemoney server - @echo 'Running ihatemoney on http://localhost:5000' -- $(PYTHON) -m ihatemoney.manage runserver -+ $(PYTHON) -m ihatemoney.manage run - - .PHONY: test - test: install-dev ## Run the tests -diff --git a/docs/installation.rst b/docs/installation.rst -index 4994499..4df70a2 100644 ---- a/docs/installation.rst -+++ b/docs/installation.rst -@@ -59,7 +59,7 @@ Test it - - Once installed, you can start a test server:: - -- ihatemoney runserver -+ ihatemoney run - - And point your browser at `http://localhost:5000 `_. - -diff --git a/ihatemoney/manage.py b/ihatemoney/manage.py -index a192844..805a07f 100755 ---- a/ihatemoney/manage.py -+++ b/ihatemoney/manage.py -@@ -5,8 +5,8 @@ import os - import random - import sys - --from flask_migrate import Migrate, MigrateCommand --from flask_script import Command, Manager, Option -+import click -+from flask.cli import FlaskGroup - from werkzeug.security import generate_password_hash - - from ihatemoney.models import Project, db -@@ -14,31 +14,48 @@ from ihatemoney.run import create_app - from ihatemoney.utils import create_jinja_env - - --class GeneratePasswordHash(Command): -+@click.group(cls=FlaskGroup, create_app=create_app) -+def cli(): -+ """IHateMoney Management script""" - -- """Get password from user and hash it without printing it in clear text.""" - -- def run(self): -- password = getpass.getpass(prompt="Password: ") -- print(generate_password_hash(password)) -- -- --class GenerateConfig(Command): -- def get_options(self): -- return [ -- Option( -- "config_file", -- choices=[ -- "ihatemoney.cfg", -- "apache-vhost.conf", -- "gunicorn.conf.py", -- "supervisord.conf", -- "nginx.conf", -- ], -- ) -+@cli.command( -+ context_settings={"ignore_unknown_options": True, "allow_extra_args": True} -+) -+@click.pass_context -+def runserver(ctx): -+ """Deprecated, use the "run" command instead""" -+ click.secho( -+ '"runserver" is deprecated, please use the standard "run" flask command', -+ fg="red", -+ ) -+ run = cli.get_command(ctx, "run") -+ ctx.forward(run) -+ -+ -+@click.command(name="generate_password_hash") -+def password_hash(): -+ """Get password from user and hash it without printing it in clear text.""" -+ password = getpass.getpass(prompt="Password: ") -+ print(generate_password_hash(password)) -+ -+ -+@click.command() -+@click.argument( -+ "config_file", -+ type=click.Choice( -+ [ -+ "ihatemoney.cfg", -+ "apache-vhost.conf", -+ "gunicorn.conf.py", -+ "supervisord.conf", -+ "nginx.conf", - ] -+ ), -+) -+def generate_config(config_file): -+ """Generate front-end server configuration""" - -- @staticmethod - def gen_secret_key(): - return "".join( - [ -@@ -49,59 +66,33 @@ class GenerateConfig(Command): - ] - ) - -- def run(self, config_file): -- env = create_jinja_env("conf-templates", strict_rendering=True) -- template = env.get_template("%s.j2" % config_file) -+ env = create_jinja_env("conf-templates", strict_rendering=True) -+ template = env.get_template(f"{config_file}.j2") - -- bin_path = os.path.dirname(sys.executable) -- pkg_path = os.path.abspath(os.path.dirname(__file__)) -+ bin_path = os.path.dirname(sys.executable) -+ pkg_path = os.path.abspath(os.path.dirname(__file__)) - -- print( -- template.render( -- pkg_path=pkg_path, -- bin_path=bin_path, -- sys_prefix=sys.prefix, -- secret_key=self.gen_secret_key(), -- ) -+ print( -+ template.render( -+ pkg_path=pkg_path, -+ bin_path=bin_path, -+ sys_prefix=sys.prefix, -+ secret_key=gen_secret_key(), - ) -- -- --class DeleteProject(Command): -- def run(self, project_name): -- demo_project = Project.query.get(project_name) -- db.session.delete(demo_project) -+ ) -+ -+ -+@cli.command() -+@click.argument("project_name") -+def delete_project(project_name): -+ """Delete a project""" -+ project = Project.query.get(project_name) -+ if project is None: -+ click.secho(f'Project "{project_name}" not found', fg="red") -+ else: -+ db.session.delete(project) - db.session.commit() - - --def main(): -- QUIET_COMMANDS = ("generate_password_hash", "generate-config") -- -- exception = None -- backup_stderr = sys.stderr -- # Hack to divert stderr for commands generating content to stdout -- # to avoid confusing the user -- if len(sys.argv) > 1 and sys.argv[1] in QUIET_COMMANDS: -- sys.stderr = open(os.devnull, "w") -- -- try: -- app = create_app() -- Migrate(app, db) -- except Exception as e: -- exception = e -- -- # Restore stderr -- sys.stderr = backup_stderr -- -- if exception: -- raise exception -- -- manager = Manager(app) -- manager.add_command("db", MigrateCommand) -- manager.add_command("generate_password_hash", GeneratePasswordHash) -- manager.add_command("generate-config", GenerateConfig) -- manager.add_command("delete-project", DeleteProject) -- manager.run() -- -- - if __name__ == "__main__": -- main() -+ cli() -diff --git a/ihatemoney/tests/tests.py b/ihatemoney/tests/tests.py -index b27fafc..23f19a6 100644 ---- a/ihatemoney/tests/tests.py -+++ b/ihatemoney/tests/tests.py -@@ -15,7 +15,7 @@ from sqlalchemy import orm - from werkzeug.security import check_password_hash, generate_password_hash - - from ihatemoney import history, models, utils --from ihatemoney.manage import DeleteProject, GenerateConfig, GeneratePasswordHash -+from ihatemoney.manage import delete_project, generate_config, password_hash - from ihatemoney.run import create_app, db, load_configuration - from ihatemoney.versioning import LoggingMode - -@@ -2157,28 +2157,24 @@ class CommandTestCase(BaseTestCase): - - raise no exception - - produce something non-empty - """ -- cmd = GenerateConfig() -- for config_file in cmd.get_options()[0].kwargs["choices"]: -- with patch("sys.stdout", new=io.StringIO()) as stdout: -- cmd.run(config_file) -- print(stdout.getvalue()) -- self.assertNotEqual(len(stdout.getvalue().strip()), 0) -+ runner = self.app.test_cli_runner() -+ for config_file in generate_config.params[0].type.choices: -+ result = runner.invoke(generate_config, config_file) -+ self.assertNotEqual(len(result.output.strip()), 0) - - def test_generate_password_hash(self): -- cmd = GeneratePasswordHash() -- with patch("sys.stdout", new=io.StringIO()) as stdout, patch( -- "getpass.getpass", new=lambda prompt: "secret" -- ): # NOQA -- cmd.run() -- print(stdout.getvalue()) -- self.assertEqual(len(stdout.getvalue().strip()), 189) -+ runner = self.app.test_cli_runner() -+ with patch("getpass.getpass", new=lambda prompt: "secret"): -+ result = runner.invoke(password_hash) -+ print(result.output.strip()) -+ self.assertEqual(len(result.output.strip()), 102) - - def test_demo_project_deletion(self): - self.create_project("demo") - self.assertEquals(models.Project.query.get("demo").name, "demo") - -- cmd = DeleteProject() -- cmd.run("demo") -+ runner = self.app.test_cli_runner() -+ runner.invoke(delete_project, "demo") - - self.assertEqual(len(models.Project.query.all()), 0) - -diff --git a/setup.cfg b/setup.cfg -index d493717..48e447c 100644 ---- a/setup.cfg -+++ b/setup.cfg -@@ -31,7 +31,6 @@ install_requires = - Flask-Mail==0.9.1 - Flask-Migrate==2.5.3 - Flask-RESTful==0.3.8 -- Flask-Script==2.0.6 - Flask-SQLAlchemy==2.4.1 - Flask-WTF==0.14.3 - WTForms==2.2.1 -@@ -51,8 +50,12 @@ dev = - zest.releaser==6.20.1 - - [options.entry_points] -+flask.commands = -+ generate_password_hash = ihatemoney.manage:password_hash -+ generate-config = ihatemoney.manage:generate_config -+ - console_scripts = -- ihatemoney = ihatemoney.manage:main -+ ihatemoney = ihatemoney.manage:cli - - paste.app_factory = - main = ihatemoney.run:main From fadabada422320a826591fefadbc66f8ee4bfac4 Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Sun, 24 Oct 2021 12:00:00 +0000 Subject: [PATCH 3/3] python3.pkgs.ihatemoney: add release notes --- .../manual/from_md/release-notes/rl-2111.section.xml | 11 +++++++++++ nixos/doc/manual/release-notes/rl-2111.section.md | 2 ++ 2 files changed, 13 insertions(+) diff --git a/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml b/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml index 73baf71f5ef5..4fff255e065b 100644 --- a/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml +++ b/nixos/doc/manual/from_md/release-notes/rl-2111.section.xml @@ -524,6 +524,17 @@ Superuser created successfully. services.geoipupdate. + + + ihatemoney has been updated to version + 5.1.1 + (release + notes). If you serve ihatemoney by HTTP rather than + HTTPS, you must set + services.ihatemoney.secureCookie + to false. + + PHP 7.3 is no longer supported due to upstream not supporting diff --git a/nixos/doc/manual/release-notes/rl-2111.section.md b/nixos/doc/manual/release-notes/rl-2111.section.md index b7fa2cf0f254..6e3084ad0f54 100644 --- a/nixos/doc/manual/release-notes/rl-2111.section.md +++ b/nixos/doc/manual/release-notes/rl-2111.section.md @@ -195,6 +195,8 @@ In addition to numerous new and upgraded packages, this release has the followin - `services.geoip-updater` was broken and has been replaced by [services.geoipupdate](options.html#opt-services.geoipupdate.enable). +- `ihatemoney` has been updated to version 5.1.1 ([release notes](https://github.com/spiral-project/ihatemoney/blob/5.1.1/CHANGELOG.rst)). If you serve ihatemoney by HTTP rather than HTTPS, you must set [services.ihatemoney.secureCookie](options.html#opt-services.ihatemoney.secureCookie) to `false`. + - PHP 7.3 is no longer supported due to upstream not supporting this version for the entire lifecycle of the 21.11 release. - Those making use of `buildBazelPackage` will need to regenerate the fetch hashes (preferred), or set `fetchConfigured = false;`.