prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  [SUGG] Little verification in Mailu setup
  Hi thanks for Mailu it is a good project.
  I submit this suggestion because i made the error and take many time to find it.
  In step 4 of Mailu Setup for Docker compose : 
  **Subnet of the docker network** it could be nice to verify if the last octet of the IP4 address is equal to 0 because if it is not the SMTP wont work.
  
  ![mailu](https://user-images.githubusercontent.com/11191723/83033266-302b2200-a037-11ea-9774-ffc326700811.jpg)
  
  Regards 
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `setup/server.py`
  Content:
  ```
  1 import flask
  2 import flask_bootstrap
  3 import redis
  4 import json
  5 import os
  6 import jinja2
  7 import uuid
  8 import string
  9 import random
  10 import ipaddress
  11 import hashlib
  12 import time
  13 
  14 
  15 version = os.getenv("this_version", "master")
  16 static_url_path = "/" + version + "/static"
  17 app = flask.Flask(__name__, static_url_path=static_url_path)
  18 flask_bootstrap.Bootstrap(app)
  19 db = redis.StrictRedis(host='redis', port=6379, db=0)
  20 
  21 
  22 def render_flavor(flavor, template, data):
  23     return flask.render_template(
  24         os.path.join(flavor, template),
  25         **data
  26     )
  27 
  28 
  29 @app.add_template_global
  30 def secret(length=16):
  31     charset = string.ascii_uppercase + string.digits
  32     return ''.join(
  33         random.SystemRandom().choice(charset)
  34         for _ in range(length)
  35     )
  36 
  37 #Original copied from https://github.com/andrewlkho/ulagen
  38 def random_ipv6_subnet():
  39     eui64 = uuid.getnode() >> 24 << 48 | 0xfffe000000 | uuid.getnode() & 0xffffff
  40     eui64_canon = "-".join([format(eui64, "02X")[i:i+2] for i in range(0, 18, 2)])
  41 
  42     h = hashlib.sha1()
  43     h.update((eui64_canon + str(time.time() - time.mktime((1900, 1, 1, 0, 0, 0, 0, 1, -1)))).encode('utf-8'))
  44     globalid = h.hexdigest()[0:10]
  45 
  46     prefix = ":".join(("fd" + globalid[0:2], globalid[2:6], globalid[6:10]))
  47     return prefix
  48 
  49 def build_app(path):
  50 
  51     app.jinja_env.trim_blocks = True
  52     app.jinja_env.lstrip_blocks = True
  53 
  54     @app.context_processor
  55     def app_context():
  56         return dict(
  57             versions=os.getenv("VERSIONS","master").split(','),
  58             stable_version = os.getenv("stable_version", "master")
  59         )
  60 
  61     prefix_bp = flask.Blueprint(version.replace(".", "_"), __name__)
  62     prefix_bp.jinja_loader = jinja2.ChoiceLoader([
  63         jinja2.FileSystemLoader(os.path.join(path, "templates")),
  64         jinja2.FileSystemLoader(os.path.join(path, "flavors"))
  65     ])
  66 
  67     root_bp = flask.Blueprint("root", __name__)
  68     root_bp.jinja_loader = jinja2.ChoiceLoader([
  69         jinja2.FileSystemLoader(os.path.join(path, "templates")),
  70         jinja2.FileSystemLoader(os.path.join(path, "flavors"))
  71     ])
  72 
  73     @prefix_bp.context_processor
  74     @root_bp.context_processor
  75     def bp_context(version=version):
  76         return dict(version=version)
  77 
  78     @prefix_bp.route("/")
  79     @root_bp.route("/")
  80     def wizard():
  81         return flask.render_template(
  82             'wizard.html',
  83             flavor="compose",
  84             steps=sorted(os.listdir(os.path.join(path, "templates", "steps", "compose"))),
  85             subnet6=random_ipv6_subnet()
  86         )
  87 
  88     @prefix_bp.route("/submit", methods=["POST"])
  89     @root_bp.route("/submit", methods=["POST"])
  90     def submit():
  91         data = flask.request.form.copy()
  92         data['uid'] = str(uuid.uuid4())
  93         try:
  94             data['dns'] = str(ipaddress.IPv4Network(data['subnet'], strict=False)[-2])
  95         except ValueError as err:
  96             return "Error while generating files: " + str(err)
  97         db.set(data['uid'], json.dumps(data))
  98         return flask.redirect(flask.url_for('.setup', uid=data['uid']))
  99 
  100     @prefix_bp.route("/setup/<uid>", methods=["GET"])
  101     @root_bp.route("/setup/<uid>", methods=["GET"])
  102     def setup(uid):
  103         data = json.loads(db.get(uid))
  104         flavor = data.get("flavor", "compose")
  105         rendered = render_flavor(flavor, "setup.html", data)
  106         return flask.render_template("setup.html", contents=rendered)
  107 
  108     @prefix_bp.route("/file/<uid>/<filepath>", methods=["GET"])
  109     @root_bp.route("/file/<uid>/<filepath>", methods=["GET"])
  110     def file(uid, filepath):
  111         data = json.loads(db.get(uid))
  112         flavor = data.get("flavor", "compose")
  113         return flask.Response(
  114             render_flavor(flavor, filepath, data),
  115             mimetype="application/text"
  116         )
  117 
  118     app.register_blueprint(prefix_bp, url_prefix="/{}".format(version))
  119     app.register_blueprint(root_bp)
  120 
  121 
  122 if __name__ == "__main__":
  123     build_app("/tmp/mailutest")
  124     app.run(debug=True)
  125
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/setup/server.py b/setup/server.py
  --- a/setup/server.py
  +++ b/setup/server.py
  @@ -10,12 +10,16 @@
   import ipaddress
   import hashlib
   import time
  -
  +import secrets
  +from flask_bootstrap import StaticCDN
   
   version = os.getenv("this_version", "master")
   static_url_path = "/" + version + "/static"
   app = flask.Flask(__name__, static_url_path=static_url_path)
  +app.secret_key = secrets.token_hex(16)
   flask_bootstrap.Bootstrap(app)
  +# Load our jQuery. Do not use jQuery 1.
  +app.extensions['bootstrap']['cdns']['jquery'] = StaticCDN()
   db = redis.StrictRedis(host='redis', port=6379, db=0)
   
   
  @@ -90,12 +94,47 @@
       def submit():
           data = flask.request.form.copy()
           data['uid'] = str(uuid.uuid4())
  +        valid = True
  +        try:
  +            ipaddress.IPv4Address(data['bind4'])
  +        except:
  +            flask.flash('Configured IPv4 address is invalid', 'error')
  +            valid = False
  +        try:
  +            ipaddress.IPv6Address(data['bind6'])
  +        except:
  +            flask.flash('Configured IPv6 address is invalid', 'error')
  +            valid = False
  +        try:
  +            ipaddress.IPv4Network(data['subnet'])
  +        except:
  +            flask.flash('Configured subnet(IPv4) is invalid', 'error')
  +            valid = False
  +        try:
  +            ipaddress.IPv6Network(data['subnet6'])
  +        except:
  +            flask.flash('Configured subnet(IPv6) is invalid', 'error')
  +            valid = False
           try:
               data['dns'] = str(ipaddress.IPv4Network(data['subnet'], strict=False)[-2])
           except ValueError as err:
  -            return "Error while generating files: " + str(err)
  -        db.set(data['uid'], json.dumps(data))
  -        return flask.redirect(flask.url_for('.setup', uid=data['uid']))
  +            flask.flash('Invalid configuration: ' + str(err))
  +            valid = False
  +        if 'api_enabled' in data:
  +            if (data['api_enabled'] == 'true'):
  +                if  data['api_token'] == '':
  +                    flask.flash('API token cannot be empty when API is enabled', 'error')
  +                    valid = False
  +        if valid:
  +            db.set(data['uid'], json.dumps(data))
  +            return flask.redirect(flask.url_for('.setup', uid=data['uid']))
  +        else:
  +            return flask.render_template(
  +                'wizard.html',
  +                flavor="compose",
  +                steps=sorted(os.listdir(os.path.join(path, "templates", "steps", "compose"))),
  +                subnet6=random_ipv6_subnet()
  +            )
   
       @prefix_bp.route("/setup/<uid>", methods=["GET"])
       @root_bp.route("/setup/<uid>", methods=["GET"])
  
verification_info: {"golden_diff": "diff --git a/setup/server.py b/setup/server.py\n--- a/setup/server.py\n+++ b/setup/server.py\n@@ -10,12 +10,16 @@\n import ipaddress\n import hashlib\n import time\n-\n+import secrets\n+from flask_bootstrap import StaticCDN\n \n version = os.getenv(\"this_version\", \"master\")\n static_url_path = \"/\" + version + \"/static\"\n app = flask.Flask(__name__, static_url_path=static_url_path)\n+app.secret_key = secrets.token_hex(16)\n flask_bootstrap.Bootstrap(app)\n+# Load our jQuery. Do not use jQuery 1.\n+app.extensions['bootstrap']['cdns']['jquery'] = StaticCDN()\n db = redis.StrictRedis(host='redis', port=6379, db=0)\n \n \n@@ -90,12 +94,47 @@\n     def submit():\n         data = flask.request.form.copy()\n         data['uid'] = str(uuid.uuid4())\n+        valid = True\n+        try:\n+            ipaddress.IPv4Address(data['bind4'])\n+        except:\n+            flask.flash('Configured IPv4 address is invalid', 'error')\n+            valid = False\n+        try:\n+            ipaddress.IPv6Address(data['bind6'])\n+        except:\n+            flask.flash('Configured IPv6 address is invalid', 'error')\n+            valid = False\n+        try:\n+            ipaddress.IPv4Network(data['subnet'])\n+        except:\n+            flask.flash('Configured subnet(IPv4) is invalid', 'error')\n+            valid = False\n+        try:\n+            ipaddress.IPv6Network(data['subnet6'])\n+        except:\n+            flask.flash('Configured subnet(IPv6) is invalid', 'error')\n+            valid = False\n         try:\n             data['dns'] = str(ipaddress.IPv4Network(data['subnet'], strict=False)[-2])\n         except ValueError as err:\n-            return \"Error while generating files: \" + str(err)\n-        db.set(data['uid'], json.dumps(data))\n-        return flask.redirect(flask.url_for('.setup', uid=data['uid']))\n+            flask.flash('Invalid configuration: ' + str(err))\n+            valid = False\n+        if 'api_enabled' in data:\n+            if (data['api_enabled'] == 'true'):\n+                if  data['api_token'] == '':\n+                    flask.flash('API token cannot be empty when API is enabled', 'error')\n+                    valid = False\n+        if valid:\n+            db.set(data['uid'], json.dumps(data))\n+            return flask.redirect(flask.url_for('.setup', uid=data['uid']))\n+        else:\n+            return flask.render_template(\n+                'wizard.html',\n+                flavor=\"compose\",\n+                steps=sorted(os.listdir(os.path.join(path, \"templates\", \"steps\", \"compose\"))),\n+                subnet6=random_ipv6_subnet()\n+            )\n \n     @prefix_bp.route(\"/setup/<uid>\", methods=[\"GET\"])\n     @root_bp.route(\"/setup/<uid>\", methods=[\"GET\"])\n", "issue": "[SUGG] Little verification in Mailu setup\nHi thanks for Mailu it is a good project.\r\nI submit this suggestion because i made the error and take many time to find it.\r\nIn step 4 of Mailu Setup for Docker compose : \r\n**Subnet of the docker network** it could be nice to verify if the last octet of the IP4 address is equal to 0 because if it is not the SMTP wont work.\r\n\r\n![mailu](https://user-images.githubusercontent.com/11191723/83033266-302b2200-a037-11ea-9774-ffc326700811.jpg)\r\n\r\nRegards \r\n\n", "before_files": [{"content": "import flask\nimport flask_bootstrap\nimport redis\nimport json\nimport os\nimport jinja2\nimport uuid\nimport string\nimport random\nimport ipaddress\nimport hashlib\nimport time\n\n\nversion = os.getenv(\"this_version\", \"master\")\nstatic_url_path = \"/\" + version + \"/static\"\napp = flask.Flask(__name__, static_url_path=static_url_path)\nflask_bootstrap.Bootstrap(app)\ndb = redis.StrictRedis(host='redis', port=6379, db=0)\n\n\ndef render_flavor(flavor, template, data):\n    return flask.render_template(\n        os.path.join(flavor, template),\n        **data\n    )\n\n\n@app.add_template_global\ndef secret(length=16):\n    charset = string.ascii_uppercase + string.digits\n    return ''.join(\n        random.SystemRandom().choice(charset)\n        for _ in range(length)\n    )\n\n#Original copied from https://github.com/andrewlkho/ulagen\ndef random_ipv6_subnet():\n    eui64 = uuid.getnode() >> 24 << 48 | 0xfffe000000 | uuid.getnode() & 0xffffff\n    eui64_canon = \"-\".join([format(eui64, \"02X\")[i:i+2] for i in range(0, 18, 2)])\n\n    h = hashlib.sha1()\n    h.update((eui64_canon + str(time.time() - time.mktime((1900, 1, 1, 0, 0, 0, 0, 1, -1)))).encode('utf-8'))\n    globalid = h.hexdigest()[0:10]\n\n    prefix = \":\".join((\"fd\" + globalid[0:2], globalid[2:6], globalid[6:10]))\n    return prefix\n\ndef build_app(path):\n\n    app.jinja_env.trim_blocks = True\n    app.jinja_env.lstrip_blocks = True\n\n    @app.context_processor\n    def app_context():\n        return dict(\n            versions=os.getenv(\"VERSIONS\",\"master\").split(','),\n            stable_version = os.getenv(\"stable_version\", \"master\")\n        )\n\n    prefix_bp = flask.Blueprint(version.replace(\".\", \"_\"), __name__)\n    prefix_bp.jinja_loader = jinja2.ChoiceLoader([\n        jinja2.FileSystemLoader(os.path.join(path, \"templates\")),\n        jinja2.FileSystemLoader(os.path.join(path, \"flavors\"))\n    ])\n\n    root_bp = flask.Blueprint(\"root\", __name__)\n    root_bp.jinja_loader = jinja2.ChoiceLoader([\n        jinja2.FileSystemLoader(os.path.join(path, \"templates\")),\n        jinja2.FileSystemLoader(os.path.join(path, \"flavors\"))\n    ])\n\n    @prefix_bp.context_processor\n    @root_bp.context_processor\n    def bp_context(version=version):\n        return dict(version=version)\n\n    @prefix_bp.route(\"/\")\n    @root_bp.route(\"/\")\n    def wizard():\n        return flask.render_template(\n            'wizard.html',\n            flavor=\"compose\",\n            steps=sorted(os.listdir(os.path.join(path, \"templates\", \"steps\", \"compose\"))),\n            subnet6=random_ipv6_subnet()\n        )\n\n    @prefix_bp.route(\"/submit\", methods=[\"POST\"])\n    @root_bp.route(\"/submit\", methods=[\"POST\"])\n    def submit():\n        data = flask.request.form.copy()\n        data['uid'] = str(uuid.uuid4())\n        try:\n            data['dns'] = str(ipaddress.IPv4Network(data['subnet'], strict=False)[-2])\n        except ValueError as err:\n            return \"Error while generating files: \" + str(err)\n        db.set(data['uid'], json.dumps(data))\n        return flask.redirect(flask.url_for('.setup', uid=data['uid']))\n\n    @prefix_bp.route(\"/setup/<uid>\", methods=[\"GET\"])\n    @root_bp.route(\"/setup/<uid>\", methods=[\"GET\"])\n    def setup(uid):\n        data = json.loads(db.get(uid))\n        flavor = data.get(\"flavor\", \"compose\")\n        rendered = render_flavor(flavor, \"setup.html\", data)\n        return flask.render_template(\"setup.html\", contents=rendered)\n\n    @prefix_bp.route(\"/file/<uid>/<filepath>\", methods=[\"GET\"])\n    @root_bp.route(\"/file/<uid>/<filepath>\", methods=[\"GET\"])\n    def file(uid, filepath):\n        data = json.loads(db.get(uid))\n        flavor = data.get(\"flavor\", \"compose\")\n        return flask.Response(\n            render_flavor(flavor, filepath, data),\n            mimetype=\"application/text\"\n        )\n\n    app.register_blueprint(prefix_bp, url_prefix=\"/{}\".format(version))\n    app.register_blueprint(root_bp)\n\n\nif __name__ == \"__main__\":\n    build_app(\"/tmp/mailutest\")\n    app.run(debug=True)\n", "path": "setup/server.py"}], "after_files": [{"content": "import flask\nimport flask_bootstrap\nimport redis\nimport json\nimport os\nimport jinja2\nimport uuid\nimport string\nimport random\nimport ipaddress\nimport hashlib\nimport time\nimport secrets\nfrom flask_bootstrap import StaticCDN\n\nversion = os.getenv(\"this_version\", \"master\")\nstatic_url_path = \"/\" + version + \"/static\"\napp = flask.Flask(__name__, static_url_path=static_url_path)\napp.secret_key = secrets.token_hex(16)\nflask_bootstrap.Bootstrap(app)\n# Load our jQuery. Do not use jQuery 1.\napp.extensions['bootstrap']['cdns']['jquery'] = StaticCDN()\ndb = redis.StrictRedis(host='redis', port=6379, db=0)\n\n\ndef render_flavor(flavor, template, data):\n    return flask.render_template(\n        os.path.join(flavor, template),\n        **data\n    )\n\n\n@app.add_template_global\ndef secret(length=16):\n    charset = string.ascii_uppercase + string.digits\n    return ''.join(\n        random.SystemRandom().choice(charset)\n        for _ in range(length)\n    )\n\n#Original copied from https://github.com/andrewlkho/ulagen\ndef random_ipv6_subnet():\n    eui64 = uuid.getnode() >> 24 << 48 | 0xfffe000000 | uuid.getnode() & 0xffffff\n    eui64_canon = \"-\".join([format(eui64, \"02X\")[i:i+2] for i in range(0, 18, 2)])\n\n    h = hashlib.sha1()\n    h.update((eui64_canon + str(time.time() - time.mktime((1900, 1, 1, 0, 0, 0, 0, 1, -1)))).encode('utf-8'))\n    globalid = h.hexdigest()[0:10]\n\n    prefix = \":\".join((\"fd\" + globalid[0:2], globalid[2:6], globalid[6:10]))\n    return prefix\n\ndef build_app(path):\n\n    app.jinja_env.trim_blocks = True\n    app.jinja_env.lstrip_blocks = True\n\n    @app.context_processor\n    def app_context():\n        return dict(\n            versions=os.getenv(\"VERSIONS\",\"master\").split(','),\n            stable_version = os.getenv(\"stable_version\", \"master\")\n        )\n\n    prefix_bp = flask.Blueprint(version.replace(\".\", \"_\"), __name__)\n    prefix_bp.jinja_loader = jinja2.ChoiceLoader([\n        jinja2.FileSystemLoader(os.path.join(path, \"templates\")),\n        jinja2.FileSystemLoader(os.path.join(path, \"flavors\"))\n    ])\n\n    root_bp = flask.Blueprint(\"root\", __name__)\n    root_bp.jinja_loader = jinja2.ChoiceLoader([\n        jinja2.FileSystemLoader(os.path.join(path, \"templates\")),\n        jinja2.FileSystemLoader(os.path.join(path, \"flavors\"))\n    ])\n\n    @prefix_bp.context_processor\n    @root_bp.context_processor\n    def bp_context(version=version):\n        return dict(version=version)\n\n    @prefix_bp.route(\"/\")\n    @root_bp.route(\"/\")\n    def wizard():\n        return flask.render_template(\n            'wizard.html',\n            flavor=\"compose\",\n            steps=sorted(os.listdir(os.path.join(path, \"templates\", \"steps\", \"compose\"))),\n            subnet6=random_ipv6_subnet()\n        )\n\n    @prefix_bp.route(\"/submit\", methods=[\"POST\"])\n    @root_bp.route(\"/submit\", methods=[\"POST\"])\n    def submit():\n        data = flask.request.form.copy()\n        data['uid'] = str(uuid.uuid4())\n        valid = True\n        try:\n            ipaddress.IPv4Address(data['bind4'])\n        except:\n            flask.flash('Configured IPv4 address is invalid', 'error')\n            valid = False\n        try:\n            ipaddress.IPv6Address(data['bind6'])\n        except:\n            flask.flash('Configured IPv6 address is invalid', 'error')\n            valid = False\n        try:\n            ipaddress.IPv4Network(data['subnet'])\n        except:\n            flask.flash('Configured subnet(IPv4) is invalid', 'error')\n            valid = False\n        try:\n            ipaddress.IPv6Network(data['subnet6'])\n        except:\n            flask.flash('Configured subnet(IPv6) is invalid', 'error')\n            valid = False\n        try:\n            data['dns'] = str(ipaddress.IPv4Network(data['subnet'], strict=False)[-2])\n        except ValueError as err:\n            flask.flash('Invalid configuration: ' + str(err))\n            valid = False\n        if 'api_enabled' in data:\n            if (data['api_enabled'] == 'true'):\n                if  data['api_token'] == '':\n                    flask.flash('API token cannot be empty when API is enabled', 'error')\n                    valid = False\n        if valid:\n            db.set(data['uid'], json.dumps(data))\n            return flask.redirect(flask.url_for('.setup', uid=data['uid']))\n        else:\n            return flask.render_template(\n                'wizard.html',\n                flavor=\"compose\",\n                steps=sorted(os.listdir(os.path.join(path, \"templates\", \"steps\", \"compose\"))),\n                subnet6=random_ipv6_subnet()\n            )\n\n    @prefix_bp.route(\"/setup/<uid>\", methods=[\"GET\"])\n    @root_bp.route(\"/setup/<uid>\", methods=[\"GET\"])\n    def setup(uid):\n        data = json.loads(db.get(uid))\n        flavor = data.get(\"flavor\", \"compose\")\n        rendered = render_flavor(flavor, \"setup.html\", data)\n        return flask.render_template(\"setup.html\", contents=rendered)\n\n    @prefix_bp.route(\"/file/<uid>/<filepath>\", methods=[\"GET\"])\n    @root_bp.route(\"/file/<uid>/<filepath>\", methods=[\"GET\"])\n    def file(uid, filepath):\n        data = json.loads(db.get(uid))\n        flavor = data.get(\"flavor\", \"compose\")\n        return flask.Response(\n            render_flavor(flavor, filepath, data),\n            mimetype=\"application/text\"\n        )\n\n    app.register_blueprint(prefix_bp, url_prefix=\"/{}\".format(version))\n    app.register_blueprint(root_bp)\n\n\nif __name__ == \"__main__\":\n    build_app(\"/tmp/mailutest\")\n    app.run(debug=True)\n", "path": "setup/server.py"}]}