Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #1439, give all atheme group founders +q #1444

Merged
merged 2 commits into from
Dec 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 19 additions & 23 deletions distrib/atheme/atheme2json.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,24 @@ def convert(infile):
'channels': defaultdict(dict),
}

# Translate channels owned by groups to being owned by the first founder of that group
# Otherwise the code crashes on networks using atheme's GroupServ
# Note: all group definitions precede channel access entries (token CA) by design, so it
# should be safe to read this in using one pass.
groups_to_user = {}
group_to_founders = defaultdict(list)

channel_to_founder = defaultdict(lambda: (None, None))

for line in infile:
line = line.rstrip('\r\n')
parts = line.split(' ')
category = parts[0]

if category == 'GACL':
# Note: all group definitions precede channel access entries (token CA) by design, so it
# should be safe to read this in using one pass.
groupname = parts[1]
user = parts[2]
flags = parts[3]
# Pick the first founder
if groupname not in groups_to_user and 'F' in flags:
groups_to_user[groupname] = user

if category == 'MU':
if 'F' in flags:
group_to_founders[groupname].append(user)
elif category == 'MU':
# user account
# MU AAAAAAAAB shivaram $1$hcspif$nCm4r3S14Me9ifsOPGuJT. [email protected] 1600134392 1600467343 +sC default
name = parts[2]
Expand All @@ -60,9 +57,7 @@ def convert(infile):
username, groupednick = parts[1], parts[2]
if username != groupednick:
user = out['users'][username]
if 'additionalNicks' not in user:
user['additionalNicks'] = []
user['additionalNicks'].append(groupednick)
user.setdefault('additionalnicks', []).append(groupednick)
elif category == 'MDU':
if parts[2] == 'private:usercloak':
username = parts[1]
Expand Down Expand Up @@ -111,18 +106,19 @@ def convert(infile):
chdata['amode'] = {}
# see libathemecore/flags.c: +o is op, +O is autoop, etc.
if 'F' in flags:
# there can only be one founder
preexisting_founder, preexisting_set_at = channel_to_founder[chname]
# If the username starts with "!", it's actually a GroupServ group.
if username.startswith('!'):
try:
group_founder = groups_to_user[username]
print(f"WARNING: flattening GroupServ group founder {username} on {chname} to first group founder {group_founder}")
except KeyError:
raise ValueError(f"Got channel {chname} owned by group {username} that has no founder?")
else:
username = group_founder

group_founders = group_to_founders.get(username)
if not group_founders:
# skip this and warn about it later
continue
# attempt to promote the first group founder to channel founder
username = group_founders[0]
# but everyone gets the +q flag
for founder in group_founders:
chdata['amode'][founder] = 'q'
# there can only be one founder
preexisting_founder, preexisting_set_at = channel_to_founder[chname]
if preexisting_founder is None or set_at < preexisting_set_at:
chdata['founder'] = username
channel_to_founder[chname] = (username, set_at)
Expand Down
22 changes: 19 additions & 3 deletions irc/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,24 @@ func doImportDBGeneric(config *Config, dbImport databaseImport, credsType Creden
tx.Set(keyCloakSecret, utils.GenerateSecretKey(), nil)

cfUsernames := make(utils.StringSet)
skeletonToUsername := make(map[string]string)
warnSkeletons := false

for username, userInfo := range dbImport.Users {
cfUsername, err := CasefoldName(username)
if err != nil {
log.Printf("invalid username %s: %v", username, err)
skeleton, skErr := Skeleton(username)
if err != nil || skErr != nil {
log.Printf("invalid username %s: %v\n", username, err)
continue
}

if existingSkelUser, ok := skeletonToUsername[skeleton]; ok {
log.Printf("Users %s and %s have confusable nicknames; this may render one or both accounts unusable\n", username, existingSkelUser)
warnSkeletons = true
} else {
skeletonToUsername[skeleton] = username
}

var certfps []string
for _, certfp := range userInfo.Certfps {
normalizedCertfp, err := utils.NormalizeCertfp(certfp)
Expand All @@ -103,7 +114,7 @@ func doImportDBGeneric(config *Config, dbImport databaseImport, credsType Creden
}
marshaledCredentials, err := json.Marshal(&credentials)
if err != nil {
log.Printf("invalid credentials for %s: %v", username, err)
log.Printf("invalid credentials for %s: %v\n", username, err)
continue
}
tx.Set(fmt.Sprintf(keyAccountExists, cfUsername), "1", nil)
Expand Down Expand Up @@ -178,6 +189,11 @@ func doImportDBGeneric(config *Config, dbImport databaseImport, credsType Creden
}
}

if warnSkeletons {
log.Printf("NOTE: you may be able to avoid confusability issues by changing the server casemapping setting to `ascii`\n")
log.Printf("However, this will prevent the use of non-ASCII Unicode characters in nicknames\n")
}

return nil
}

Expand Down