Compare commits
	
		
			10 Commits
		
	
	
		
			eb5c71968a
			...
			webform
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| d90a3218b2 | |||
| b73ab237e3 | |||
| 1e045964fa | |||
| b159820f6c | |||
| 690484a097 | |||
| fe5b9e1f25 | |||
| 71f84cd0a9 | |||
| e4752fd039 | |||
| 117c93deaf | |||
| 6d0040415b | 
							
								
								
									
										1
									
								
								Pipfile
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Pipfile
									
									
									
									
									
								
							@@ -8,6 +8,7 @@ name = "pypi"
 | 
				
			|||||||
[packages]
 | 
					[packages]
 | 
				
			||||||
aiosmtpd = "*"
 | 
					aiosmtpd = "*"
 | 
				
			||||||
python-jata = "*"
 | 
					python-jata = "*"
 | 
				
			||||||
 | 
					asyncbasehttp = "*"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[requires]
 | 
					[requires]
 | 
				
			||||||
python_version = "3"
 | 
					python_version = "3"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										10
									
								
								Pipfile.lock
									
									
									
										generated
									
									
									
								
							@@ -1,7 +1,7 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "_meta": {
 | 
					    "_meta": {
 | 
				
			||||||
        "hash": {
 | 
					        "hash": {
 | 
				
			||||||
            "sha256": "5c16e20a67c73101d465516d657e21c6c1d3f853ae16dcfe782b7f9e8ba139e5"
 | 
					            "sha256": "6b224d3d72187a39e4fba357ffb4b162dc28994bd869c7960fcfd5acbb56c959"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "pipfile-spec": 6,
 | 
					        "pipfile-spec": 6,
 | 
				
			||||||
        "requires": {
 | 
					        "requires": {
 | 
				
			||||||
@@ -24,6 +24,14 @@
 | 
				
			|||||||
            "index": "pypi",
 | 
					            "index": "pypi",
 | 
				
			||||||
            "version": "==1.4.4.post2"
 | 
					            "version": "==1.4.4.post2"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        "asyncbasehttp": {
 | 
				
			||||||
 | 
					            "hashes": [
 | 
				
			||||||
 | 
					                "sha256:2cea7b61113bb1e69d1c90f32919f004e7f56a7e1e2955e8a6286ce40f9da188",
 | 
				
			||||||
 | 
					                "sha256:70fb983c4df630a9b63081cb8ef6d2e06beb51c89f42a88da6c9a9c7ebf9fb89"
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            "index": "pypi",
 | 
				
			||||||
 | 
					            "version": "==1.0"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        "atpublic": {
 | 
					        "atpublic": {
 | 
				
			||||||
            "hashes": [
 | 
					            "hashes": [
 | 
				
			||||||
                "sha256:0f40433219e124edf115c6c363808ca6f0e1cfa7d160d86b2fb94793086d1294",
 | 
					                "sha256:0f40433219e124edf115c6c363808ca6f0e1cfa7d160d86b2fb94793086d1294",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								jsdev/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								jsdev/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					tmp
 | 
				
			||||||
							
								
								
									
										44
									
								
								jsdev/air.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								jsdev/air.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					root = "."
 | 
				
			||||||
 | 
					testdata_dir = "testdata"
 | 
				
			||||||
 | 
					tmp_dir = "tmp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[build]
 | 
				
			||||||
 | 
					  args_bin = []
 | 
				
			||||||
 | 
					  bin = "./tmp/main"
 | 
				
			||||||
 | 
					  cmd = "cp ./restart.sh ./tmp/main"
 | 
				
			||||||
 | 
					  delay = 0
 | 
				
			||||||
 | 
					  exclude_dir = ["assets", "tmp", "vendor", "testdata"]
 | 
				
			||||||
 | 
					  exclude_file = []
 | 
				
			||||||
 | 
					  exclude_regex = ["_test.go"]
 | 
				
			||||||
 | 
					  exclude_unchanged = false
 | 
				
			||||||
 | 
					  follow_symlink = false
 | 
				
			||||||
 | 
					  full_bin = ""
 | 
				
			||||||
 | 
					  include_dir = []
 | 
				
			||||||
 | 
					  include_ext = ["go", "tpl", "tmpl", "html"]
 | 
				
			||||||
 | 
					  include_file = []
 | 
				
			||||||
 | 
					  kill_delay = "0s"
 | 
				
			||||||
 | 
					  log = "build-errors.log"
 | 
				
			||||||
 | 
					  poll = false
 | 
				
			||||||
 | 
					  poll_interval = 0
 | 
				
			||||||
 | 
					  rerun = false
 | 
				
			||||||
 | 
					  rerun_delay = 500
 | 
				
			||||||
 | 
					  send_interrupt = false
 | 
				
			||||||
 | 
					  stop_on_error = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[color]
 | 
				
			||||||
 | 
					  app = ""
 | 
				
			||||||
 | 
					  build = "yellow"
 | 
				
			||||||
 | 
					  main = "magenta"
 | 
				
			||||||
 | 
					  runner = "green"
 | 
				
			||||||
 | 
					  watcher = "cyan"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[log]
 | 
				
			||||||
 | 
					  main_only = false
 | 
				
			||||||
 | 
					  time = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[misc]
 | 
				
			||||||
 | 
					  clean_on_exit = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[screen]
 | 
				
			||||||
 | 
					  clear_on_rebuild = false
 | 
				
			||||||
 | 
					  keep_scroll = true
 | 
				
			||||||
							
								
								
									
										473
									
								
								jsdev/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										473
									
								
								jsdev/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,473 @@
 | 
				
			|||||||
 | 
					<!doctype html>
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					    <head>
 | 
				
			||||||
 | 
					        <meta charset="utf-8">
 | 
				
			||||||
 | 
					        <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
				
			||||||
 | 
					        <link rel="icon" href="data:;base64,iVBORw0KGgo=">
 | 
				
			||||||
 | 
					        <title>Mail4one Web config</title>
 | 
				
			||||||
 | 
					        <script type="application/json" id="m41config">
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "matches": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  "name": "mydomain",
 | 
				
			||||||
 | 
					                  "addr_rexs": [
 | 
				
			||||||
 | 
					                    ".*@mydomain.com",
 | 
				
			||||||
 | 
					                    ".*@m.mydomain.com"
 | 
				
			||||||
 | 
					                  ]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  "name": "personal",
 | 
				
			||||||
 | 
					                  "addrs": [
 | 
				
			||||||
 | 
					                    "first.last@mydomain.com",
 | 
				
			||||||
 | 
					                    "secret.name@mydomain.com"
 | 
				
			||||||
 | 
					                  ]
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              ],
 | 
				
			||||||
 | 
					              "boxes": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  "name": "spam",
 | 
				
			||||||
 | 
					                  "rules": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      "match_name": "mydomain",
 | 
				
			||||||
 | 
					                      "negate": true,
 | 
				
			||||||
 | 
					                      "stop_check": true
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  ]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  "name": "important",
 | 
				
			||||||
 | 
					                  "rules": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      "match_name": "personal"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  ]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  "name": "all",
 | 
				
			||||||
 | 
					                  "rules": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      "match_name": "default_match_all"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  ]
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              ],
 | 
				
			||||||
 | 
					              "users": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  "username": "mymobile",
 | 
				
			||||||
 | 
					                  "password_hash": "AFTY5EVN7AX47ZL7UMH3BETYWFBTAV3XHR73CEFAJBPN2NIHPWDZHV2UQSMSPHSQQ2A2BFQBNC77VL7F2UKATQNJZGYLCSU6C43UQDAQXWXSWNGAEPGIMG2F3QDKBXL3MRHY6K2BPID64ZR6LABLPVSF",
 | 
				
			||||||
 | 
					                  "mbox": "important"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  "username": "mydesk",
 | 
				
			||||||
 | 
					                  "password_hash": "AFTY5EVN7AX47ZL7UMH3BETYWFBTAV3XHR73CEFAJBPN2NIHPWDZHV2UQSMSPHSQQ2A2BFQBNC77VL7F2UKATQNJZGYLCSU6C43UQDAQXWXSWNGAEPGIMG2F3QDKBXL3MRHY6K2BPID64ZR6LABLPVSF",
 | 
				
			||||||
 | 
					                  "mbox": "all"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              ]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        </script>
 | 
				
			||||||
 | 
					        <style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					td {
 | 
				
			||||||
 | 
					    padding: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            table {
 | 
				
			||||||
 | 
					                border: 2px solid;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            thead {
 | 
				
			||||||
 | 
					                background-color: orange;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            h1.page-title {
 | 
				
			||||||
 | 
					                background-color: orange;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            h3 {
 | 
				
			||||||
 | 
					                text-align: center;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            .outer {
 | 
				
			||||||
 | 
					                display: flex;
 | 
				
			||||||
 | 
					                justify-content: center;
 | 
				
			||||||
 | 
					                background: grey;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            .inner {
 | 
				
			||||||
 | 
					                display: flex;
 | 
				
			||||||
 | 
					                flex-direction: column;
 | 
				
			||||||
 | 
					                align-items: center;
 | 
				
			||||||
 | 
					                border: 2px solid;
 | 
				
			||||||
 | 
					                background-color: lightyellow;
 | 
				
			||||||
 | 
					                padding: 10px;
 | 
				
			||||||
 | 
					                justify-content: space-around;
 | 
				
			||||||
 | 
					                margin: 10px;
 | 
				
			||||||
 | 
					                width: 1200px;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            .m41-box {
 | 
				
			||||||
 | 
					                display: grid;
 | 
				
			||||||
 | 
					                grid-template-columns: 1fr 3fr;
 | 
				
			||||||
 | 
					                margin: 10px;
 | 
				
			||||||
 | 
					                // background-color: lightblue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            .multiline {
 | 
				
			||||||
 | 
					                text-align: left;
 | 
				
			||||||
 | 
					                padding: 5px;
 | 
				
			||||||
 | 
					                padding-left: 15px;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #web-cfg-matches {
 | 
				
			||||||
 | 
					                width: 90%;
 | 
				
			||||||
 | 
					                text-align: center;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #web-cfg-matches tbody tr:nth-of-type(odd) {
 | 
				
			||||||
 | 
					                background: lightblue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #web-cfg-matches tbody tr:nth-of-type(even) {
 | 
				
			||||||
 | 
					                background: lightgrey;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #web-cfg-boxes {
 | 
				
			||||||
 | 
					                text-align: center;
 | 
				
			||||||
 | 
					                width: 90%;
 | 
				
			||||||
 | 
					                // display: grid;
 | 
				
			||||||
 | 
					                // grid-template-columns: 1fr ;
 | 
				
			||||||
 | 
					                //justify-content: space-around;
 | 
				
			||||||
 | 
					                // justify-content: flex-start;
 | 
				
			||||||
 | 
					                // background-color: blue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #web-cfg-boxes tbody:nth-of-type(odd) {
 | 
				
			||||||
 | 
					                background: lightblue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #web-cfg-boxes tbody:nth-of-type(even) {
 | 
				
			||||||
 | 
					                background: lightgrey;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #web-cfg-boxes tbody tr td div.dummy{
 | 
				
			||||||
 | 
					                display: none;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #web-cfg-boxes tbody tr td div button.dummy {
 | 
				
			||||||
 | 
					                display: none;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #web-cfg-boxes tbody:first-of-type tr td.box div button.up.dummy {
 | 
				
			||||||
 | 
					                display: block;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #web-cfg-boxes tbody:first-of-type tr td.box div button.up.real {
 | 
				
			||||||
 | 
					                display: none;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #web-cfg-boxes tbody:last-of-type tr td.box div button.down.dummy {
 | 
				
			||||||
 | 
					                display: block;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #web-cfg-boxes tbody:last-of-type tr td.box div button.down.real {
 | 
				
			||||||
 | 
					                display: none;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #web-cfg-boxes tbody:only-of-type tr td.box div.real {
 | 
				
			||||||
 | 
					                display: none;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            #web-cfg-boxes tbody:only-of-type tr td.box div.dummy {
 | 
				
			||||||
 | 
					                display: flex;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            td.box {
 | 
				
			||||||
 | 
					                display: flex;
 | 
				
			||||||
 | 
					                justify-content: center;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            .button-group {
 | 
				
			||||||
 | 
					                display: flex;
 | 
				
			||||||
 | 
					                justify-content: center;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        </style>
 | 
				
			||||||
 | 
					        <script type="application/javascript">
 | 
				
			||||||
 | 
					            "use strict"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Globals
 | 
				
			||||||
 | 
					            let server_config
 | 
				
			||||||
 | 
					            let matches_table
 | 
				
			||||||
 | 
					            let match_row_template
 | 
				
			||||||
 | 
					            let boxes_table
 | 
				
			||||||
 | 
					            let box_template
 | 
				
			||||||
 | 
					            // let rule_template
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            function initGlobals() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                server_config = JSON.parse(document.getElementById('m41config').text)
 | 
				
			||||||
 | 
					                matches_table = document.getElementById("web-cfg-matches")
 | 
				
			||||||
 | 
					                match_row_template = document.getElementById("web-cfg-matches-row")
 | 
				
			||||||
 | 
					                boxes_table = document.getElementById("web-cfg-boxes")
 | 
				
			||||||
 | 
					                box_template = document.getElementById("web-cfg-box")
 | 
				
			||||||
 | 
					                // rule_template = document.getElementById("web-cfg-boxes-rule-li")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            function populate_match_table(matches_config) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                for (const { name: match_name, addrs, addr_rexs } of matches_config) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    const [match_type, match_values] = (() => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        if (addrs != undefined) {
 | 
				
			||||||
 | 
					                            return ["addrs", addrs]
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            return ["addr_rexs", addr_rexs]
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    })()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    addMatchRow()
 | 
				
			||||||
 | 
					                    const last_row = matches_table.tBodies[0].lastElementChild
 | 
				
			||||||
 | 
					                    const [ ,name_cell, {firstElementChild: type_select}, value_cell ] = last_row.cells
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    name_cell.innerText = match_name
 | 
				
			||||||
 | 
					                    type_select.value = match_type
 | 
				
			||||||
 | 
					                    value_cell.innerText = match_values.join("\n")
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            function extract_match_table() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let matches = []
 | 
				
			||||||
 | 
					                for (let row of matches_table.tBodies[0].rows) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    const [ ,name_cell, {firstElementChild: type_select}, value_cell ] = row.cells
 | 
				
			||||||
 | 
					                    let m = {"name" : name_cell.innerText}
 | 
				
			||||||
 | 
					                    switch (type_select.value) {
 | 
				
			||||||
 | 
					                        case "addrs":
 | 
				
			||||||
 | 
					                            m["addrs"] = value_cell.innerText.split("\n")
 | 
				
			||||||
 | 
					                            break
 | 
				
			||||||
 | 
					                        case "addr_rexs":
 | 
				
			||||||
 | 
					                            m["addr_rexs"] = value_cell.innerText.split("\n")
 | 
				
			||||||
 | 
					                            break
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    matches.push(m)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return matches
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            function addMatchRow() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let row_clone = match_row_template.content.cloneNode(true)
 | 
				
			||||||
 | 
					                matches_table.tBodies[0].appendChild(row_clone)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            function populate_boxes_list(boxes_config) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                for (const {name:box_name, rules} of boxes_config) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    addBox()
 | 
				
			||||||
 | 
					                    const tbody = boxes_table.lastElementChild
 | 
				
			||||||
 | 
					                    const box = tbody.firstElementChild
 | 
				
			||||||
 | 
					                    // console.log(box)
 | 
				
			||||||
 | 
					                    const [, 
 | 
				
			||||||
 | 
					                        {children: [box_text, ]},
 | 
				
			||||||
 | 
					                        ,
 | 
				
			||||||
 | 
					                        {firstElementChild: match_select},
 | 
				
			||||||
 | 
					                        {firstElementChild: negate_check},
 | 
				
			||||||
 | 
					                        {firstElementChild: stop_check},
 | 
				
			||||||
 | 
					                    ] = box.children
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    box_text.value = box_name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    const [first_rule, ...rest] = rules
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    const {match_name, negate = false, stop = false} = first_rule
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    match_select.value = match_name
 | 
				
			||||||
 | 
					                    negate_check.checked = negate
 | 
				
			||||||
 | 
					                    stop_check.checked = stop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    for (const {match_name, negate = false, stop_check = false} of rest ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        addRule(box)
 | 
				
			||||||
 | 
					                        const rule = tbody.lastElementChild
 | 
				
			||||||
 | 
					                        const [, 
 | 
				
			||||||
 | 
					                            {firstElementChild: match_select}, 
 | 
				
			||||||
 | 
					                            {firstElementChild: negateCheck}, 
 | 
				
			||||||
 | 
					                            {firstElementChild: stopCheck} 
 | 
				
			||||||
 | 
					                        ] = rule.children
 | 
				
			||||||
 | 
					                        match_select.value = match_name
 | 
				
			||||||
 | 
					                        negate_check.checked = negate
 | 
				
			||||||
 | 
					                        stop_check.checked = stop
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            function addRule(box) {
 | 
				
			||||||
 | 
					                box.parentElement.appendChild(box.cloneNode(true))
 | 
				
			||||||
 | 
					                box.children[0].rowSpan++;
 | 
				
			||||||
 | 
					                box.children[1].rowSpan++;
 | 
				
			||||||
 | 
					                const newrule = box.parentElement.lastElementChild
 | 
				
			||||||
 | 
					                newrule.removeClass("fist-tr")
 | 
				
			||||||
 | 
					                newrule.firstElementChild.remove()
 | 
				
			||||||
 | 
					                newrule.firstElementChild.remove()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            function addBox() {
 | 
				
			||||||
 | 
					                let box_clone = box_template.content.cloneNode(true)
 | 
				
			||||||
 | 
					                boxes_table.appendChild(box_clone)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            function moveUp(button) {
 | 
				
			||||||
 | 
					                const li = button.parentElement.parentElement.parentElement
 | 
				
			||||||
 | 
					                if (li.previousElementSibling != null) {
 | 
				
			||||||
 | 
					                    li.parentNode.insertBefore(li, li.previousElementSibling)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            function moveDown(button) {
 | 
				
			||||||
 | 
					                const li = button.parentElement.parentElement.parentElement
 | 
				
			||||||
 | 
					                if (li.nextElementSibling != null) {
 | 
				
			||||||
 | 
					                    li.parentNode.insertBefore(li.nextElementSibling, li)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            function main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                initGlobals()
 | 
				
			||||||
 | 
					                populate_match_table(server_config["matches"])
 | 
				
			||||||
 | 
					                save()
 | 
				
			||||||
 | 
					                document.getElementById("before").innerText = JSON.stringify(server_config["matches"], null, 2)
 | 
				
			||||||
 | 
					                populate_boxes_list(server_config["boxes"])
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            function save() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                const matches = extract_match_table() 
 | 
				
			||||||
 | 
					                document.getElementById("after").innerText = JSON.stringify(matches, null, 2)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        </script>
 | 
				
			||||||
 | 
					    </head>
 | 
				
			||||||
 | 
					    <body onload="main()">
 | 
				
			||||||
 | 
					        <template id="web-cfg-matches-row">
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					                <td><button onClick="this.parentElement.parentElement.remove()">✗</button></td>
 | 
				
			||||||
 | 
					                <td contentEditable></td>
 | 
				
			||||||
 | 
					                <td>
 | 
				
			||||||
 | 
					                    <select>
 | 
				
			||||||
 | 
					                        <option value="addrs">List of addresses</option>
 | 
				
			||||||
 | 
					                        <option value="addr_rexs">List of regexes for addresses</option>
 | 
				
			||||||
 | 
					                    </select>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					                <td contentEditable class="multiline"></td>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <template id="web-cfg-box">
 | 
				
			||||||
 | 
					            <tbody>
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                    <td class="box">
 | 
				
			||||||
 | 
					                        <div class="button-group dummy">
 | 
				
			||||||
 | 
					                            <button disabled>✗</button>
 | 
				
			||||||
 | 
					                            <button disabled>↑</button>
 | 
				
			||||||
 | 
					                            <button disabled>↓</button>
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                        <div class="button-group real">
 | 
				
			||||||
 | 
					                            <button onClick="this.parentElement.parentElement.parentElement.parentElement.remove()">✗</button>
 | 
				
			||||||
 | 
					                            <button onClick="moveBoxUp(this)" class="real up">↑</button>
 | 
				
			||||||
 | 
					                            <button disabled class="dummy up">↑</button>
 | 
				
			||||||
 | 
					                            <button onClick="moveBoxDown(this)" class="real down">↓</button>
 | 
				
			||||||
 | 
					                            <button disabled class="dummy down">↓</button>
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                        <button onClick="addRule(this.parentElement.parentElement)">+</button>
 | 
				
			||||||
 | 
					                    </td>
 | 
				
			||||||
 | 
					                    <td contentEditable>
 | 
				
			||||||
 | 
					                        <input type="text" contentEditable>
 | 
				
			||||||
 | 
					                    </td>
 | 
				
			||||||
 | 
					                    <td class="rule">
 | 
				
			||||||
 | 
					                        <div class="button-group dummy">
 | 
				
			||||||
 | 
					                            <button disabled>✗</button>
 | 
				
			||||||
 | 
					                            <button disabled>↑</button>
 | 
				
			||||||
 | 
					                            <button disabled>↓</button>
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                        <div class="button-group real">
 | 
				
			||||||
 | 
					                            <button onClick="this.parentElement.parentElement.parentElement.remove()">✗</button>
 | 
				
			||||||
 | 
					                            <button onClick="moveRuleUp(this)" class="real up">↑</button>
 | 
				
			||||||
 | 
					                            <button disabled class="dummy up">↑</button>
 | 
				
			||||||
 | 
					                            <button onClick="moveRuleDown(this)" class="real down">↓</button>
 | 
				
			||||||
 | 
					                            <button disabled class="dummy down">↓</button>
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                    </td>
 | 
				
			||||||
 | 
					                    <td>
 | 
				
			||||||
 | 
					                        <select></select>
 | 
				
			||||||
 | 
					                    </td>
 | 
				
			||||||
 | 
					                    <td>
 | 
				
			||||||
 | 
					                        <input type=checkbox>
 | 
				
			||||||
 | 
					                    </td>
 | 
				
			||||||
 | 
					                    <td>
 | 
				
			||||||
 | 
					                        <input type=checkbox>
 | 
				
			||||||
 | 
					                    </td>
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
 | 
					            </tbody>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <div class="outer">
 | 
				
			||||||
 | 
					            <div class="inner">
 | 
				
			||||||
 | 
					                <h1 class="page-title">Mail4one Web config</h1>
 | 
				
			||||||
 | 
					                <div id="top-menu">
 | 
				
			||||||
 | 
					                    <button onClick="save()">Previous</button>
 | 
				
			||||||
 | 
					                    <button onClick="save()">Matches</button>
 | 
				
			||||||
 | 
					                    <button onClick="save()">Boxes</button>
 | 
				
			||||||
 | 
					                    <button onClick="save()">Users</button>
 | 
				
			||||||
 | 
					                    <button onClick="save()">JSON</button>
 | 
				
			||||||
 | 
					                    <button onClick="save()">Next</button>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                <div id="match-page">
 | 
				
			||||||
 | 
					                    <h3> Matches </h3>
 | 
				
			||||||
 | 
					                    <table id="web-cfg-matches">
 | 
				
			||||||
 | 
					                        <thead>
 | 
				
			||||||
 | 
					                            <tr>
 | 
				
			||||||
 | 
					                                <th>
 | 
				
			||||||
 | 
					                                    <button onClick="addMatchRow()">+</button>
 | 
				
			||||||
 | 
					                                </th>
 | 
				
			||||||
 | 
					                                <th>Match</th>
 | 
				
			||||||
 | 
					                                <th>Type</th>
 | 
				
			||||||
 | 
					                                <th>Values</th>
 | 
				
			||||||
 | 
					                            </tr>
 | 
				
			||||||
 | 
					                        </thead>
 | 
				
			||||||
 | 
					                        <tbody>
 | 
				
			||||||
 | 
					                        </tbody>
 | 
				
			||||||
 | 
					                    </table>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <div id=box-page">
 | 
				
			||||||
 | 
					                    <h3>Boxes</h3>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    <table id="web-cfg-boxes">
 | 
				
			||||||
 | 
					                        <thead>
 | 
				
			||||||
 | 
					                            <tr>
 | 
				
			||||||
 | 
					                                <th><button onClick="addBox()">+</button></th>
 | 
				
			||||||
 | 
					                                <th>Mailbox</th>
 | 
				
			||||||
 | 
					                                <th></th>
 | 
				
			||||||
 | 
					                                <th>Match</th>
 | 
				
			||||||
 | 
					                                <th>Invert</th>
 | 
				
			||||||
 | 
					                                <th>Stop</th>
 | 
				
			||||||
 | 
					                            </tr>
 | 
				
			||||||
 | 
					                        </thead>
 | 
				
			||||||
 | 
					                    </table>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <hr>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <h3>Before</h3>
 | 
				
			||||||
 | 
					                <pre id="before"></pre>
 | 
				
			||||||
 | 
					                <hr>
 | 
				
			||||||
 | 
					                <h3>After</h3>
 | 
				
			||||||
 | 
					                <pre id="after"></pre>
 | 
				
			||||||
 | 
					                <hr>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										11
									
								
								jsdev/restart.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										11
									
								
								jsdev/restart.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# kill "$(cat current.pid)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# echo "starting python server"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					python3 -m http.server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# echo $! > current.pid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# echo "started python server"
 | 
				
			||||||
@@ -16,6 +16,8 @@ VERSION = b"\x01"
 | 
				
			|||||||
SALT_LEN = 30
 | 
					SALT_LEN = 30
 | 
				
			||||||
KEY_LEN = 64  # This is python default
 | 
					KEY_LEN = 64  # This is python default
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# len(VERSION) + SALT_LEN + KEY_LEN should be multiple of 5 to avoid base32 padding
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def gen_pwhash(password: str) -> str:
 | 
					def gen_pwhash(password: str) -> str:
 | 
				
			||||||
    salt = os.urandom(SALT_LEN)
 | 
					    salt = os.urandom(SALT_LEN)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@ from getpass import getpass
 | 
				
			|||||||
from .smtp import create_smtp_server_starttls, create_smtp_server
 | 
					from .smtp import create_smtp_server_starttls, create_smtp_server
 | 
				
			||||||
from .pop3 import create_pop_server
 | 
					from .pop3 import create_pop_server
 | 
				
			||||||
from .version import VERSION
 | 
					from .version import VERSION
 | 
				
			||||||
 | 
					from .web_config import create_web_config_server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from . import config
 | 
					from . import config
 | 
				
			||||||
from . import pwhash
 | 
					from . import pwhash
 | 
				
			||||||
@@ -98,6 +99,14 @@ async def a_main(cfg: config.Config) -> None:
 | 
				
			|||||||
                ssl_context=get_tls_context(smtp.tls),
 | 
					                ssl_context=get_tls_context(smtp.tls),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
            servers.append(smtp_server)
 | 
					            servers.append(smtp_server)
 | 
				
			||||||
 | 
					        elif scfg.server_type == "web_config":
 | 
				
			||||||
 | 
					            web = config.ServerCfg(scfg)
 | 
				
			||||||
 | 
					            web_server = await create_web_config_server(
 | 
				
			||||||
 | 
					                host=get_host(web.host),
 | 
				
			||||||
 | 
					                port=web.port,
 | 
				
			||||||
 | 
					                ssl_context=get_tls_context(web.tls),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            servers.append(web_server)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            logging.error(f"Unknown server {scfg.server_type=}")
 | 
					            logging.error(f"Unknown server {scfg.server_type=}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										88
									
								
								mail4one/template_web_config.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								mail4one/template_web_config.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
				
			|||||||
 | 
					<!doctype html>
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					    <head>
 | 
				
			||||||
 | 
					        <title>Mail4one Web config</title>
 | 
				
			||||||
 | 
					        <script type="application/json" id="m41config">
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              "matches": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  "name": "mydomain",
 | 
				
			||||||
 | 
					                  "addr_rexs": [
 | 
				
			||||||
 | 
					                    ".*@mydomain.com",
 | 
				
			||||||
 | 
					                    ".*@m.mydomain.com"
 | 
				
			||||||
 | 
					                  ]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  "name": "personal",
 | 
				
			||||||
 | 
					                  "addrs": [
 | 
				
			||||||
 | 
					                    "first.last@mydomain.com",
 | 
				
			||||||
 | 
					                    "secret.name@mydomain.com"
 | 
				
			||||||
 | 
					                  ]
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              ],
 | 
				
			||||||
 | 
					              "boxes": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  "name": "spam",
 | 
				
			||||||
 | 
					                  "rules": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      "match_name": "mydomain",
 | 
				
			||||||
 | 
					                      "negate": true,
 | 
				
			||||||
 | 
					                      "stop_check": true
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  ]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  "name": "important",
 | 
				
			||||||
 | 
					                  "rules": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      "match_name": "personal"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  ]
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  "name": "all",
 | 
				
			||||||
 | 
					                  "rules": [
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      "match_name": "default_match_all"
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  ]
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              ],
 | 
				
			||||||
 | 
					              "users": [
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  "username": "mymobile",
 | 
				
			||||||
 | 
					                  "password_hash": "AFTY5EVN7AX47ZL7UMH3BETYWFBTAV3XHR73CEFAJBPN2NIHPWDZHV2UQSMSPHSQQ2A2BFQBNC77VL7F2UKATQNJZGYLCSU6C43UQDAQXWXSWNGAEPGIMG2F3QDKBXL3MRHY6K2BPID64ZR6LABLPVSF",
 | 
				
			||||||
 | 
					                  "mbox": "important"
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  "username": "mydesk",
 | 
				
			||||||
 | 
					                  "password_hash": "AFTY5EVN7AX47ZL7UMH3BETYWFBTAV3XHR73CEFAJBPN2NIHPWDZHV2UQSMSPHSQQ2A2BFQBNC77VL7F2UKATQNJZGYLCSU6C43UQDAQXWXSWNGAEPGIMG2F3QDKBXL3MRHY6K2BPID64ZR6LABLPVSF",
 | 
				
			||||||
 | 
					                  "mbox": "all"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              ]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        </script>
 | 
				
			||||||
 | 
					        <script type="application/javascript">
 | 
				
			||||||
 | 
					            function main() {
 | 
				
			||||||
 | 
					                document.write("hello world")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        </script>
 | 
				
			||||||
 | 
					    </head>
 | 
				
			||||||
 | 
					    <body onload="main()">
 | 
				
			||||||
 | 
					        <template id="web-cfg-matches-row">
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					                <td>Name</td>
 | 
				
			||||||
 | 
					                <td>Type</td>
 | 
				
			||||||
 | 
					                <td>Values</td>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <h1>Mail4one Web config</h1>
 | 
				
			||||||
 | 
					        <table id="web-cfg-matches">
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					                <th>Name</th>
 | 
				
			||||||
 | 
					                <th>Type</th>
 | 
				
			||||||
 | 
					                <th>Values</th>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					        </table>
 | 
				
			||||||
 | 
					    </body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										80
									
								
								mail4one/web_config.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								mail4one/web_config.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					import asyncio
 | 
				
			||||||
 | 
					from asyncbasehttp import request_handler, Request, Response, RequestHandler
 | 
				
			||||||
 | 
					from typing import Optional, Tuple
 | 
				
			||||||
 | 
					import ssl
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					from pprint import pprint
 | 
				
			||||||
 | 
					import http
 | 
				
			||||||
 | 
					from base64 import b64decode
 | 
				
			||||||
 | 
					from .pwhash import gen_pwhash, parse_hash, PWInfo, check_pass
 | 
				
			||||||
 | 
					import pkgutil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_template() -> bytes:
 | 
				
			||||||
 | 
					    if data:= pkgutil.get_data('mail4one', 'template_web_config.html'):
 | 
				
			||||||
 | 
					        return data
 | 
				
			||||||
 | 
					    raise Exception("Failed to get template data from 'template_web_config.html'")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_dummy_pwinfo() -> PWInfo:
 | 
				
			||||||
 | 
					    pwhash = gen_pwhash("world")
 | 
				
			||||||
 | 
					    return parse_hash(pwhash)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class WebonfigHandler(RequestHandler):
 | 
				
			||||||
 | 
					    def __init__(self, username: str, pwinfo: PWInfo):
 | 
				
			||||||
 | 
					        self.username = username.encode()
 | 
				
			||||||
 | 
					        self.pwinfo = pwinfo
 | 
				
			||||||
 | 
					        self.auth_required = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def do_auth(self, req: Request) -> Tuple[bool, Optional[Response]]:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        def resp_unauthorized():
 | 
				
			||||||
 | 
					            resp = Response.no_body_response(http.HTTPStatus.UNAUTHORIZED)
 | 
				
			||||||
 | 
					            resp.add_header("WWW-Authenticate", 'Basic realm="Mail4one"')
 | 
				
			||||||
 | 
					            return resp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auth_header = req.headers["Authorization"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not auth_header:
 | 
				
			||||||
 | 
					            return False, resp_unauthorized()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not auth_header.startswith("Basic "):
 | 
				
			||||||
 | 
					            logging.error("Authorization header malformed")
 | 
				
			||||||
 | 
					            return False, Response.no_body_response(http.HTTPStatus.BAD_REQUEST)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        userpassb64 = auth_header[len("Basic ") :]
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            userpass = b64decode(userpassb64)
 | 
				
			||||||
 | 
					            username, password = userpass.split(b":")
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            logging.exception("bad request")
 | 
				
			||||||
 | 
					            return False, Response.no_body_response(http.HTTPStatus.BAD_REQUEST)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if username == self.username and check_pass(password.decode(), self.pwinfo):
 | 
				
			||||||
 | 
					            return True, None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return False, resp_unauthorized()
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async def process_request(self, req: Request) -> Response:
 | 
				
			||||||
 | 
					        if self.auth_required:
 | 
				
			||||||
 | 
					            ok, resp = self.do_auth(req)
 | 
				
			||||||
 | 
					            if not ok:
 | 
				
			||||||
 | 
					                if resp:
 | 
				
			||||||
 | 
					                    return resp
 | 
				
			||||||
 | 
					                else: # To silence mypy
 | 
				
			||||||
 | 
					                    raise Exception("Something went wrong!")
 | 
				
			||||||
 | 
					        return Response.create_ok_response(get_template())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					async def create_web_config_server(
 | 
				
			||||||
 | 
					    host: str, port: int, ssl_context: Optional[ssl.SSLContext]
 | 
				
			||||||
 | 
					) -> asyncio.Server:
 | 
				
			||||||
 | 
					    logging.info(f"template: {get_template().decode()}")
 | 
				
			||||||
 | 
					    logging.info(f"Starting Webconfig server {host=}, {port=}, {ssl_context != None=}")
 | 
				
			||||||
 | 
					    return await asyncio.start_server(
 | 
				
			||||||
 | 
					        WebonfigHandler("hello", get_dummy_pwinfo()),
 | 
				
			||||||
 | 
					        host=host,
 | 
				
			||||||
 | 
					        port=port,
 | 
				
			||||||
 | 
					        ssl=ssl_context,
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
		Reference in New Issue
	
	Block a user