This commit is contained in:
2025-09-26 15:54:02 +03:00
parent 0050a4130b
commit ac56849a3b
2 changed files with 115 additions and 118 deletions

View File

@@ -14,31 +14,32 @@ def getenv(name):
print(f"[ERROR] Missing environment variable {name}. You should NOT run this script by hand, please use systemd mastodon-kanidm-sync.service.") print(f"[ERROR] Missing environment variable {name}. You should NOT run this script by hand, please use systemd mastodon-kanidm-sync.service.")
exit(1) exit(1)
# Import configuration # Import configuration
KANIDM_URL = getenv("KANIDM_URL") KANIDM_URL = getenv("KANIDM_URL")
KANIDM_TOKEN = read_file(getenv("KANIDM_TOKEN_PATH")).strip() KANIDM_TOKEN = read_file(getenv("KANIDM_TOKEN_PATH")).strip()
OWNER_USERNAME = getenv("OWNER_USERNAME") OWNER_USERNAME = getenv("OWNER_USERNAME")
SLEEP_TIME = int(getenv("SLEEP_TIME"))
# Fetch kanidm users list from userdata file def sync_mastodon():
# Userdata file is json list with information about what users are configured by kanidm # Fetch kanidm users list from userdata file
try: # Userdata file is json list with information about what users are configured by kanidm
try:
USERDATA = read_file(getenv("USERDATA_FILE_PATH")).strip() USERDATA = read_file(getenv("USERDATA_FILE_PATH")).strip()
userdata = json.loads(USERDATA) userdata = json.loads(USERDATA)
print("[INFO] ") print("[INFO] ")
except FileNotFoundError: except FileNotFoundError:
userdata = [] userdata = []
# Load database # Load database
conn = ps.connect( conn = ps.connect(
dbname=getenv("POSTGRES_DBNAME"), dbname=getenv("POSTGRES_DBNAME"),
user=getenv("POSTGRES_USER"), user=getenv("POSTGRES_USER"),
host=getenv("POSTGRES_HOST") host=getenv("POSTGRES_HOST")
) )
# Fetch current userdata from database # Fetch current userdata from database
cur = conn.cursor() cur = conn.cursor()
cur.execute(''' cur.execute('''
SELECT identities.uid, users.id, user_roles.name SELECT identities.uid, users.id, user_roles.name
FROM users FROM users
JOIN identities JOIN identities
@@ -46,29 +47,29 @@ cur.execute('''
LEFT JOIN user_roles LEFT JOIN user_roles
ON users.role_id = user_roles.id; ON users.role_id = user_roles.id;
''' '''
) )
state = cur.fetchall() state = cur.fetchall()
users = {} users = {}
for i in state: for i in state:
users[i[0]] = { users[i[0]] = {
"id": i[1], "id": i[1],
"role": i[2], "role": i[2],
"isKanidmUser": False "isKanidmUser": False
} }
# Fetch Kanidm userdata # Fetch Kanidm userdata
kanidm_users_raw = requests.get( kanidm_users_raw = requests.get(
f"{KANIDM_URL}/v1/person", f"{KANIDM_URL}/v1/person",
headers={ headers={
"Authorization": f"Bearer {KANIDM_TOKEN}", "Authorization": f"Bearer {KANIDM_TOKEN}",
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
timeout=5, timeout=5,
).json() ).json()
def give_role(uid, role, putUserdata = True): def give_role(uid, role, putUserdata = True):
if (uid not in userdata) and (putUserdata): if (uid not in userdata) and (putUserdata):
userdata.append(uid) userdata.append(uid)
users[uid]["isKanidmUser"] = True users[uid]["isKanidmUser"] = True
@@ -76,7 +77,7 @@ def give_role(uid, role, putUserdata = True):
print(f"[INFO] {uid} is marked as {role}") print(f"[INFO] {uid} is marked as {role}")
for i in kanidm_users_raw: for i in kanidm_users_raw:
i = i["attrs"] i = i["attrs"]
for uid in i["name"]: # [user].attrs.name is a list for uid in i["name"]: # [user].attrs.name is a list
if uid in users: # Don't apply anything for users who have no mastodon access (sp.mastodon.users) or didn't register if uid in users: # Don't apply anything for users who have no mastodon access (sp.mastodon.users) or didn't register
@@ -98,19 +99,19 @@ for i in kanidm_users_raw:
give_role(uid, None, False) give_role(uid, None, False)
userdata.remove(uid) userdata.remove(uid)
print("[DEBUG]", users) print("[DEBUG]", users)
# Fetch RoleIDs # Fetch RoleIDs
cur = conn.cursor() cur = conn.cursor()
cur.execute("SELECT id, name FROM user_roles;") cur.execute("SELECT id, name FROM user_roles;")
roles_raw = cur.fetchall() roles_raw = cur.fetchall()
roles = {} roles = {}
for i in roles_raw: for i in roles_raw:
roles[i[1]] = i[0] roles[i[1]] = i[0]
# Give roles # Give roles
for uid in users: for uid in users:
if not users[uid]["isKanidmUser"]: if not users[uid]["isKanidmUser"]:
continue continue
@@ -124,19 +125,23 @@ for uid in users:
print("[DEBUG] SQL:", sqlcommand) print("[DEBUG] SQL:", sqlcommand)
cur.execute(sqlcommand) cur.execute(sqlcommand)
conn.commit() conn.commit()
cur.close() cur.close()
conn.close() conn.close()
print("[INFO] Final userdata.json file content: ", userdata) print("[INFO] Final userdata.json file content: ", userdata)
def write_userdata(mode): def write_userdata(mode):
with open(getenv("USERDATA_FILE_PATH"), mode) as f: with open(getenv("USERDATA_FILE_PATH"), mode) as f:
f.write(json.dumps(userdata)) f.write(json.dumps(userdata))
f.close() f.close()
try: try:
write_userdata("w") write_userdata("w")
except FileNotFoundError: except FileNotFoundError:
print("[INFO] userdata.json file doesn't exist. Creating it") print("[INFO] userdata.json file doesn't exist. Creating it")
write_userdata("x") write_userdata("x")
while True:
sync_mastodon()
time.sleep(SLEEP_TIME)

View File

@@ -91,7 +91,7 @@ in
enableUnixSocket = false; enableUnixSocket = false;
configureNginx = true; configureNginx = true;
database.createLocally = true; database.createLocally = true;
streamingProcesses = 3; streamingProcesses = 2;
smtp = { smtp = {
createLocally = false; createLocally = false;
@@ -105,8 +105,7 @@ in
port = 465; port = 465;
}; };
extraConfig = { extraConfig = {
# "SMTP_ENABLE_STARTTLS" = "never"; "SMTP_ENABLE_STARTTLS_AUTO" = "true"; # Simple NixOS MailServer doesn't allow connections without SSL
"SMTP_ENABLE_STARTTLS_AUTO" = "true";
"SMTP_ENABLE_STARTTLS" = "always"; "SMTP_ENABLE_STARTTLS" = "always";
"SMTP_TLS" = "true"; "SMTP_TLS" = "true";
"SMTP_SSL" = "true"; "SMTP_SSL" = "true";
@@ -114,14 +113,7 @@ in
"DISALLOW_UNAUTHENTICATED_API_ACCESS" = lib.boolToString cfg.dissallowUnauthenticatedAPI; "DISALLOW_UNAUTHENTICATED_API_ACCESS" = lib.boolToString cfg.dissallowUnauthenticatedAPI;
}; };
}; };
users.users.mastodon.isSystemUser = lib.mkForce false;
users.users.mastodon.isNormalUser = lib.mkForce true;
users.groups."email-users" = {};
users.users."noreply.mastodon" = {
isSystemUser = true;
group = "email-users";
};
selfprivacy.emails."noreply.mastodon" = { selfprivacy.emails."noreply.mastodon" = {
hashedPasswordFile = secrets.hashedPasswordFile; hashedPasswordFile = secrets.hashedPasswordFile;
systemdTargets = [ "mastodon-email-password-setup.service" ]; systemdTargets = [ "mastodon-email-password-setup.service" ];
@@ -155,7 +147,6 @@ in
services.mastodon-kanidm-sync = { services.mastodon-kanidm-sync = {
after = [ after = [
# "mastodon.service" # TODO: ??
"postgresql.service" "postgresql.service"
"kanidm.service" "kanidm.service"
]; ];
@@ -173,6 +164,7 @@ in
POSTGRES_HOST = db.host; POSTGRES_HOST = db.host;
USERDATA_FILE_PATH = "/var/lib/mastodon/.userdata.json"; USERDATA_FILE_PATH = "/var/lib/mastodon/.userdata.json";
OWNER_USERNAME = sp.username; OWNER_USERNAME = sp.username;
SLEEP_TIME = "30";
}; };
serviceConfig = { serviceConfig = {
Slice = "mastodon.slice"; Slice = "mastodon.slice";