mirror of
https://github.com/BigfootACA/arch-image-builder.git
synced 2024-11-11 07:57:53 +08:00
271 lines
6.0 KiB
Python
271 lines
6.0 KiB
Python
import io
|
|
from typing import Self
|
|
from builder.lib.serializable import SerializableDict, SerializableList
|
|
|
|
|
|
def zero2empty(num: int) -> str:
|
|
"""
|
|
Convert number to string, when zero return empty
|
|
"""
|
|
return str(num) if num != 0 else ""
|
|
|
|
|
|
def none2empty(val: str) -> str:
|
|
"""
|
|
Return a string, when None return empty
|
|
"""
|
|
return val if val else ""
|
|
|
|
|
|
class UserEntry(SerializableDict):
|
|
name: str = None
|
|
|
|
def from_line(self, line: str): pass
|
|
|
|
def to_line(self) -> str: pass
|
|
|
|
|
|
class UserFile(SerializableList):
|
|
def load_line(self, line: str): pass
|
|
|
|
def unload(self): pass
|
|
|
|
def load_str(self, content: str | list[str]) -> Self:
|
|
"""
|
|
Load whole file as string
|
|
"""
|
|
if type(content) is str:
|
|
content = content.split("\n")
|
|
for line in content:
|
|
line = line.strip()
|
|
if line.startswith("#"): continue
|
|
if len(line) <= 0: continue
|
|
self.load_line(line)
|
|
return self
|
|
|
|
def load_fp(self, fp: io.TextIOWrapper) -> Self:
|
|
self.load_str(fp.readlines())
|
|
return self
|
|
|
|
def load_file(self, file: str) -> Self:
|
|
with open(file, "r") as f:
|
|
self.load_fp(f)
|
|
return self
|
|
|
|
def from_str(self, content: str) -> Self:
|
|
self.unload()
|
|
self.load_str(content)
|
|
return self
|
|
|
|
def from_fp(self, fp: io.TextIOWrapper) -> Self:
|
|
self.unload()
|
|
self.load_fp(fp)
|
|
return self
|
|
|
|
def from_file(self, file: str) -> Self:
|
|
self.unload()
|
|
self.load_file(file)
|
|
return self
|
|
|
|
|
|
class ShadowEntry(UserEntry):
|
|
name: str = None
|
|
password: str = None
|
|
last_change: int = 0
|
|
min_age: int = 0
|
|
max_age: int = 0
|
|
warning_period: int = 0
|
|
inactivity_period: int = 0
|
|
expiration: int = 0
|
|
|
|
def from_line(self, line: str):
|
|
values = line.split(":")
|
|
if len(values) != 8:
|
|
raise ValueError("fields mismatch")
|
|
self.name = values[0]
|
|
self.password = values[1]
|
|
self.last_change = int(values[2]) if len(values[2]) > 0 else 0
|
|
self.min_age = int(values[3]) if len(values[3]) > 0 else 0
|
|
self.max_age = int(values[4]) if len(values[4]) > 0 else 0
|
|
self.warning_period = int(values[5]) if len(values[5]) > 0 else 0
|
|
self.inactivity_period = int(values[6]) if len(values[6]) > 0 else 0
|
|
self.expiration = int(values[7]) if len(values[7]) > 0 else 0
|
|
|
|
def to_line(self) -> str:
|
|
values = [
|
|
none2empty(self.name),
|
|
none2empty(self.password),
|
|
zero2empty(self.last_change),
|
|
zero2empty(self.min_age),
|
|
zero2empty(self.max_age),
|
|
zero2empty(self.warning_period),
|
|
zero2empty(self.inactivity_period),
|
|
zero2empty(self.expiration),
|
|
]
|
|
return (":".join(values)) + "\n"
|
|
|
|
|
|
class GshadowEntry(UserEntry):
|
|
name: str = None
|
|
password: str = None
|
|
admins: list[str] = None
|
|
members: list[str] = None
|
|
|
|
@property
|
|
def admin(self):
|
|
return ",".join(self.admins)
|
|
|
|
@admin.setter
|
|
def admin(self, val: str):
|
|
self.admins = val.split(",")
|
|
|
|
@property
|
|
def member(self):
|
|
return ",".join(self.members)
|
|
|
|
@member.setter
|
|
def member(self, val: str):
|
|
self.members = val.split(",")
|
|
|
|
def from_line(self, line: str):
|
|
values = line.split(":")
|
|
if len(values) != 4:
|
|
raise ValueError("fields mismatch")
|
|
self.name = values[0]
|
|
self.password = values[1]
|
|
self.admin = values[2]
|
|
self.member = values[3]
|
|
|
|
def to_line(self) -> str:
|
|
values = [
|
|
none2empty(self.name),
|
|
none2empty(self.password),
|
|
none2empty(self.admin),
|
|
none2empty(self.member),
|
|
]
|
|
return (":".join(values)) + "\n"
|
|
|
|
|
|
class PasswdEntry(UserEntry):
|
|
name: str = None
|
|
password: str = None
|
|
uid: int = -1
|
|
gid: int = -1
|
|
comment: str = None
|
|
home: str = None
|
|
shell: str = None
|
|
|
|
def from_line(self, line: str):
|
|
values = line.split(":")
|
|
if len(values) != 7:
|
|
raise ValueError("fields mismatch")
|
|
self.name = values[0]
|
|
self.password = values[1]
|
|
self.uid = int(values[2])
|
|
self.gid = int(values[3])
|
|
self.comment = values[4]
|
|
self.home = values[5]
|
|
self.shell = values[6]
|
|
|
|
def to_line(self) -> str:
|
|
values = [
|
|
none2empty(self.name),
|
|
none2empty(self.password),
|
|
str(self.uid),
|
|
str(self.gid),
|
|
none2empty(self.comment),
|
|
none2empty(self.home),
|
|
none2empty(self.shell),
|
|
]
|
|
return (":".join(values)) + "\n"
|
|
|
|
|
|
class GroupEntry(UserEntry):
|
|
name: str = None
|
|
password: str = None
|
|
gid: int = -1
|
|
users: list[str] = None
|
|
|
|
@property
|
|
def user(self):
|
|
return ",".join(self.users)
|
|
|
|
@user.setter
|
|
def user(self, val: str):
|
|
self.users = val.split(",")
|
|
|
|
def from_line(self, line: str):
|
|
values = line.split(":")
|
|
if len(values) != 4:
|
|
raise ValueError("fields mismatch")
|
|
self.name = values[0]
|
|
self.password = values[1]
|
|
self.gid = int(values[2])
|
|
self.user = values[3]
|
|
|
|
def to_line(self) -> str:
|
|
values = [
|
|
none2empty(self.name),
|
|
none2empty(self.password),
|
|
str(self.gid),
|
|
none2empty(self.user),
|
|
]
|
|
return (":".join(values)) + "\n"
|
|
|
|
|
|
class ShadowFile(list[ShadowEntry], UserFile):
|
|
def unload(self): self.clear()
|
|
|
|
def load_line(self, line: str):
|
|
ent = ShadowEntry()
|
|
ent.from_line(line)
|
|
self.append(ent)
|
|
|
|
def lookup_name(self, name: str) -> ShadowEntry:
|
|
return next((e for e in self if e.name == name), None)
|
|
|
|
|
|
class GshadowFile(list[GshadowEntry], UserFile):
|
|
def unload(self): self.clear()
|
|
|
|
def load_line(self, line: str):
|
|
ent = GshadowEntry()
|
|
ent.from_line(line)
|
|
self.append(ent)
|
|
|
|
def lookup_name(self, name: str) -> GshadowEntry:
|
|
return next((e for e in self if e.name == name), None)
|
|
|
|
|
|
class PasswdFile(list[PasswdEntry], UserFile):
|
|
def unload(self): self.clear()
|
|
|
|
def load_line(self, line: str):
|
|
ent = PasswdEntry()
|
|
ent.from_line(line)
|
|
self.append(ent)
|
|
|
|
def lookup_name(self, name: str) -> PasswdEntry:
|
|
return next((e for e in self if e.name == name), None)
|
|
|
|
def lookup_uid(self, uid: int) -> PasswdEntry:
|
|
return next((e for e in self if e.uid == uid), None)
|
|
|
|
def lookup_gid(self, gid: int) -> PasswdEntry:
|
|
return next((e for e in self if e.gid == gid), None)
|
|
|
|
|
|
class GroupFile(list[GroupEntry], UserFile):
|
|
def unload(self): self.clear()
|
|
|
|
def load_line(self, line: str):
|
|
ent = GroupEntry()
|
|
ent.from_line(line)
|
|
self.append(ent)
|
|
|
|
def lookup_name(self, name: str) -> GroupEntry:
|
|
return next((e for e in self if e.name == name), None)
|
|
|
|
def lookup_gid(self, gid: int) -> GroupEntry:
|
|
return next((e for e in self if e.gid == gid), None)
|