mirror of
https://github.com/chatmail/relay.git
synced 2026-05-11 00:14:36 +00:00
Compare commits
9 Commits
hpk/shift-
...
scripts
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f89b52d5b | ||
|
|
9da375cf5c | ||
|
|
8086e2ee2f | ||
|
|
1b88e0d9d0 | ||
|
|
db6df34703 | ||
|
|
a907da9907 | ||
|
|
14649c37fd | ||
|
|
28fe373489 | ||
|
|
1942ad3cef |
@@ -16,5 +16,5 @@ For DKIM you must add a DNS entry as in /etc/opendkim/selector.txt (where select
|
|||||||
## Run with pyinfra
|
## Run with pyinfra
|
||||||
|
|
||||||
```
|
```
|
||||||
CHATMAIL_DOMAIN=c1.testrun.org pyinfra c1.testrun.org deploy.py
|
CHATMAIL_DOMAIN=c1.testrun.org pyinfra --ssh-user root c1.testrun.org deploy.py
|
||||||
```
|
```
|
||||||
|
|||||||
11
c1-inv.py
11
c1-inv.py
@@ -1,11 +0,0 @@
|
|||||||
|
|
||||||
chatmail = [
|
|
||||||
(
|
|
||||||
"c1.testrun.org",
|
|
||||||
{
|
|
||||||
"ssh_user": "root",
|
|
||||||
"domain": "c1.testrun.org",
|
|
||||||
"dkim_selector": "2023",
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -8,7 +8,11 @@ def main():
|
|||||||
mail_server = os.getenv("CHATMAIL_SERVER", mail_domain)
|
mail_server = os.getenv("CHATMAIL_SERVER", mail_domain)
|
||||||
dkim_selector = os.getenv("CHATMAIL_DKIM_SELECTOR", "2023")
|
dkim_selector = os.getenv("CHATMAIL_DKIM_SELECTOR", "2023")
|
||||||
|
|
||||||
|
assert mail_domain
|
||||||
|
assert mail_server
|
||||||
|
assert dkim_selector
|
||||||
|
|
||||||
deploy_chatmail(mail_domain, mail_server, dkim_selector)
|
deploy_chatmail(mail_domain, mail_server, dkim_selector)
|
||||||
|
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|||||||
3
scripts/deploy.sh
Executable file
3
scripts/deploy.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
export CHATMAIL_DOMAIN="${1:-c1.testrun.org}"
|
||||||
|
venv/bin/pyinfra --ssh-user root "$CHATMAIL_DOMAIN" deploy.py
|
||||||
4
scripts/init.sh
Executable file
4
scripts/init.sh
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
python3 -m venv venv
|
||||||
|
venv/bin/pip install pyinfra
|
||||||
|
venv/bin/pip install -e .
|
||||||
@@ -8,7 +8,9 @@ end
|
|||||||
-- call out to python program to actually manage authentication for dovecot
|
-- call out to python program to actually manage authentication for dovecot
|
||||||
|
|
||||||
function chatctl_verify(user, password)
|
function chatctl_verify(user, password)
|
||||||
local handle = io.popen("python doveauth.py hexauth "..escape(user).." "..escape(password))
|
local cmd = "python3 /home/vmail/chatctl hexauth "..escape(user).." "..escape(password)
|
||||||
|
print("executing: "..cmd)
|
||||||
|
local handle = io.popen(cmd)
|
||||||
local result = handle:read("*a")
|
local result = handle:read("*a")
|
||||||
handle:close()
|
handle:close()
|
||||||
return split_chatctl(result)
|
return split_chatctl(result)
|
||||||
@@ -16,32 +18,27 @@ end
|
|||||||
|
|
||||||
function chatctl_lookup(user)
|
function chatctl_lookup(user)
|
||||||
assert(user)
|
assert(user)
|
||||||
local handle = io.popen("python doveauth.py hexlookup "..escape(user))
|
local handle = io.popen("python3 /home/vmail/chatctl hexlookup "..escape(user))
|
||||||
local result = handle:read("*a")
|
local result = handle:read("*a")
|
||||||
handle:close()
|
handle:close()
|
||||||
return split_chatctl(result)
|
return split_chatctl(result)
|
||||||
end
|
end
|
||||||
|
|
||||||
function get_extra_dovecot_output(res)
|
function get_extra_dovecot_output(res)
|
||||||
return {homedir=res.homedir, uid=res.uid, gid=res.gid}
|
return {home=res.home, uid=res.uid, gid=res.gid}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function auth_passdb_verify(request, password)
|
function auth_password_verify(request, password)
|
||||||
local res = chatctl_verify(request.user, password)
|
local res = chatctl_verify(request.user, password)
|
||||||
|
-- request:log_error("auth_password_verify "..request.user.." "..password)
|
||||||
if res.status == "ok" then
|
if res.status == "ok" then
|
||||||
|
local extra = get_extra_dovecot_output(res)
|
||||||
return dovecot.auth.PASSDB_RESULT_OK, get_extra_dovecot_output(res)
|
return dovecot.auth.PASSDB_RESULT_OK, get_extra_dovecot_output(res)
|
||||||
end
|
end
|
||||||
return dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH, ""
|
return dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH, ""
|
||||||
end
|
end
|
||||||
|
|
||||||
function auth_passdb_lookup(request)
|
|
||||||
local res = chatctl_lookup(request.user)
|
|
||||||
if res.status == "ok" then
|
|
||||||
return dovecot.auth.PASSDB_RESULT_OK, get_extra_dovecot_output(res)
|
|
||||||
end
|
|
||||||
return dovecot.auth.PASSDB_RESULT_USER_UNKNOWN, "no such user"
|
|
||||||
end
|
|
||||||
|
|
||||||
function auth_userdb_lookup(request)
|
function auth_userdb_lookup(request)
|
||||||
local res = chatctl_lookup(request.user)
|
local res = chatctl_lookup(request.user)
|
||||||
|
|||||||
@@ -4,21 +4,17 @@ import sys
|
|||||||
|
|
||||||
|
|
||||||
def get_user_data(user):
|
def get_user_data(user):
|
||||||
if user == b"link2xt@instant2.testrun.org":
|
if user == "link2xt@c1.testrun.org":
|
||||||
return dict(
|
return dict(
|
||||||
homedir="/home/vmail/link2xt",
|
|
||||||
uid="vmail",
|
uid="vmail",
|
||||||
gid="vmail",
|
gid="vmail",
|
||||||
password=b"Ahyei6ie",
|
password="Ahyei6ie",
|
||||||
)
|
)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
|
||||||
def create_user(user, password):
|
def create_user(user, password):
|
||||||
assert isinstance(password, bytes)
|
return dict(home=f"/home/vmail/{user}", uid="vmail", gid="vmail", password=password)
|
||||||
return dict(
|
|
||||||
homedir=f"/home/vmail/{user}", uid="vmail", gid="vmail", password=password
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def verify_user(user, password):
|
def verify_user(user, password):
|
||||||
@@ -51,11 +47,11 @@ def dump_result(res):
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if sys.argv[1] == "hexauth":
|
if sys.argv[1] == "hexauth":
|
||||||
login = base64.b16decode(sys.argv[2])
|
login = base64.b16decode(sys.argv[2]).decode()
|
||||||
password = base64.b16decode(sys.argv[3])
|
password = base64.b16decode(sys.argv[3]).decode()
|
||||||
res = verify_user(login, password)
|
res = verify_user(login, password)
|
||||||
dump_result(res)
|
dump_result(res)
|
||||||
elif sys.argv[1] == "hexlookup":
|
elif sys.argv[1] == "hexlookup":
|
||||||
login = base64.b16decode(sys.argv[2])
|
login = base64.b16decode(sys.argv[2]).decode()
|
||||||
res = lookup_user(login)
|
res = lookup_user(login)
|
||||||
dump_result(res)
|
dump_result(res)
|
||||||
|
|||||||
@@ -4,6 +4,11 @@ protocols = imap lmtp
|
|||||||
|
|
||||||
auth_mechanisms = plain
|
auth_mechanisms = plain
|
||||||
|
|
||||||
|
auth_verbose = yes
|
||||||
|
auth_debug = yes
|
||||||
|
auth_debug_passwords = yes
|
||||||
|
auth_verbose_passwords = plain
|
||||||
|
|
||||||
# Authentication for system users.
|
# Authentication for system users.
|
||||||
passdb {
|
passdb {
|
||||||
driver = lua
|
driver = lua
|
||||||
|
|||||||
@@ -15,19 +15,19 @@ dovecot = {
|
|||||||
|
|
||||||
-- Tests for testing the lua<->python interaction
|
-- Tests for testing the lua<->python interaction
|
||||||
|
|
||||||
function test_passdb_verify_ok(user, password)
|
function test_password_verify_ok(user, password)
|
||||||
local res, extra = auth_passdb_verify({user=user}, password)
|
local res, extra = auth_password_verify({user=user}, password)
|
||||||
assert(res==dovecot.auth.PASSDB_RESULT_OK)
|
assert(res==dovecot.auth.PASSDB_RESULT_OK)
|
||||||
assert(extra.uid == "vmail")
|
assert(extra.uid == "vmail")
|
||||||
assert(extra.gid == "vmail")
|
assert(extra.gid == "vmail")
|
||||||
-- assert(extra.homedir == "/home/vmail/link2xt")
|
-- assert(extra.homedir == "/home/vmail/link2xt")
|
||||||
print("OK test_passdb_verify_ok "..user.." "..password)
|
print("OK test_password_verify_ok "..user.." "..password)
|
||||||
end
|
end
|
||||||
|
|
||||||
function test_passdb_verify_mismatch(user, password)
|
function test_password_verify_mismatch(user, password)
|
||||||
local res = auth_passdb_verify({user=user}, password)
|
local res = auth_password_verify({user=user}, password)
|
||||||
assert(res == dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH)
|
assert(res == dovecot.auth.PASSDB_RESULT_PASSWORD_MISMATCH)
|
||||||
print("OK test_passdb_verify_mismatch "..user.." "..password)
|
print("OK test_password_verify_mismatch "..user.." "..password)
|
||||||
end
|
end
|
||||||
|
|
||||||
function test_userdb_lookup_ok(user)
|
function test_userdb_lookup_ok(user)
|
||||||
@@ -67,10 +67,12 @@ function test_split_chatctl()
|
|||||||
end
|
end
|
||||||
|
|
||||||
test_split_chatctl()
|
test_split_chatctl()
|
||||||
test_passdb_verify_ok("link2xt@instant2.testrun.org", "Ahyei6ie")
|
test_password_verify_ok("link2xt@c1.testrun.org", "Ahyei6ie")
|
||||||
test_passdb_verify_mismatch("link2xt@instant2.testrun.org", "Aqwlek")
|
test_password_verify_mismatch("link2xt@c1.testrun.org", "Aqwlek")
|
||||||
test_userdb_lookup_ok("link2xt@instant2.testrun.org")
|
test_userdb_lookup_ok("link2xt@c1.testrun.org")
|
||||||
test_userdb_lookup_mismatch("wlekqjlew@xyz.org")
|
test_userdb_lookup_mismatch("wlekqjlew@xyz.org")
|
||||||
test_passdb_lookup_ok("link2xt@instant2.testrun.org")
|
|
||||||
test_passdb_lookup_mismatch("llqkwjelqwe@xyz.org")
|
-- probably not needed by dovecot?
|
||||||
|
-- test_passdb_lookup_ok("link2xt@c1.testrun.org")
|
||||||
|
-- test_passdb_lookup_mismatch("llqkwjelqwe@xyz.org")
|
||||||
|
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ from doveauth import get_user_data, verify_user
|
|||||||
|
|
||||||
|
|
||||||
def test_basic():
|
def test_basic():
|
||||||
data = get_user_data(b"link2xt@instant2.testrun.org")
|
data = get_user_data("link2xt@c1.testrun.org")
|
||||||
assert data
|
assert data
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.xfail(reason="no persistence yet")
|
@pytest.mark.xfail(reason="no persistence yet")
|
||||||
def test_verify_or_create():
|
def test_verify_or_create():
|
||||||
res = verify_user(b"newuser1@something.org", b"kajdlkajsldk12l3kj1983")
|
res = verify_user("newuser1@something.org", "kajdlkajsldk12l3kj1983")
|
||||||
assert res["status"] == "ok"
|
assert res["status"] == "ok"
|
||||||
res = verify_user(b"newuser1@something.org", b"kajdlqweqwe")
|
res = verify_user("newuser1@something.org", "kajdlqweqwe")
|
||||||
assert res["status"] == "fail"
|
assert res["status"] == "fail"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
28
tests/test_online_login.py
Normal file
28
tests/test_online_login.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import pytest
|
||||||
|
import imaplib
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def conn():
|
||||||
|
return connect("c1.testrun.org")
|
||||||
|
|
||||||
|
|
||||||
|
def login(conn, user, password):
|
||||||
|
print("trying to login", user, password)
|
||||||
|
conn.login(user, password)
|
||||||
|
|
||||||
|
|
||||||
|
def connect(host):
|
||||||
|
print(f"connecting to {host}")
|
||||||
|
conn = imaplib.IMAP4_SSL(host)
|
||||||
|
return conn
|
||||||
|
|
||||||
|
|
||||||
|
def test_login_ok(conn):
|
||||||
|
login(conn, "link2xt@c1.testrun.org", "Ahyei6ie")
|
||||||
|
|
||||||
|
|
||||||
|
def test_login_fail(conn):
|
||||||
|
with pytest.raises(imaplib.IMAP4.error) as excinfo:
|
||||||
|
login(conn, "link2xt@c1.testrun.org", "qweqwe")
|
||||||
|
assert "AUTHENTICATIONFAILED" in str(excinfo)
|
||||||
Reference in New Issue
Block a user