forked from baron/baron-sso
Implement tenant import and RP auto login policies
This commit is contained in:
196
backend/internal/domain/hanmac_email.go
Normal file
196
backend/internal/domain/hanmac_email.go
Normal file
@@ -0,0 +1,196 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var hanmacSurnameRomanization = map[rune]string{
|
||||
'한': "han",
|
||||
'김': "kim",
|
||||
'이': "lee",
|
||||
'박': "park",
|
||||
'최': "choi",
|
||||
'정': "jung",
|
||||
'조': "cho",
|
||||
'강': "kang",
|
||||
'윤': "yoon",
|
||||
'장': "jang",
|
||||
'임': "lim",
|
||||
'림': "lim",
|
||||
'신': "shin",
|
||||
'오': "oh",
|
||||
'서': "seo",
|
||||
'권': "kwon",
|
||||
'황': "hwang",
|
||||
'안': "ahn",
|
||||
'송': "song",
|
||||
'전': "jeon",
|
||||
'홍': "hong",
|
||||
'유': "yoo",
|
||||
'고': "ko",
|
||||
'문': "moon",
|
||||
'양': "yang",
|
||||
'손': "son",
|
||||
'배': "bae",
|
||||
'백': "baek",
|
||||
'허': "heo",
|
||||
'남': "nam",
|
||||
'심': "sim",
|
||||
'노': "noh",
|
||||
'하': "ha",
|
||||
'곽': "kwak",
|
||||
'성': "sung",
|
||||
'차': "cha",
|
||||
'주': "joo",
|
||||
'우': "woo",
|
||||
'구': "koo",
|
||||
'민': "min",
|
||||
'류': "ryu",
|
||||
'나': "na",
|
||||
'진': "jin",
|
||||
'지': "ji",
|
||||
'엄': "um",
|
||||
'채': "chae",
|
||||
'원': "won",
|
||||
'천': "cheon",
|
||||
'방': "bang",
|
||||
'공': "gong",
|
||||
'현': "hyun",
|
||||
'함': "ham",
|
||||
'여': "yeo",
|
||||
'추': "choo",
|
||||
'도': "do",
|
||||
'소': "so",
|
||||
'석': "seok",
|
||||
'선': "sun",
|
||||
'설': "seol",
|
||||
'마': "ma",
|
||||
'길': "gil",
|
||||
'연': "yeon",
|
||||
'위': "wi",
|
||||
'표': "pyo",
|
||||
'명': "myung",
|
||||
'기': "ki",
|
||||
'반': "ban",
|
||||
'라': "ra",
|
||||
'왕': "wang",
|
||||
'금': "geum",
|
||||
'옥': "ok",
|
||||
'육': "yook",
|
||||
'인': "in",
|
||||
'맹': "maeng",
|
||||
'제': "je",
|
||||
'모': "mo",
|
||||
'탁': "tak",
|
||||
'국': "guk",
|
||||
'어': "eo",
|
||||
'은': "eun",
|
||||
'편': "pyeon",
|
||||
'용': "yong",
|
||||
}
|
||||
|
||||
var hanmacInitialRomanization = []string{
|
||||
"g", "g", "n", "d", "d", "r", "m", "b", "b", "s",
|
||||
"s", "y", "j", "j", "c", "k", "t", "p", "h",
|
||||
}
|
||||
|
||||
func SplitEmailDomain(email string) (string, string, error) {
|
||||
normalized := strings.ToLower(strings.TrimSpace(email))
|
||||
at := strings.Index(normalized, "@")
|
||||
if at < 0 {
|
||||
return "", "", errors.New("email must contain @")
|
||||
}
|
||||
if strings.Count(normalized, "@") != 1 {
|
||||
return "", "", errors.New("email must contain one @")
|
||||
}
|
||||
localPart := strings.TrimSpace(normalized[:at])
|
||||
domainPart := strings.TrimSpace(normalized[at+1:])
|
||||
if domainPart == "" || !strings.Contains(domainPart, ".") {
|
||||
return "", "", errors.New("email domain is invalid")
|
||||
}
|
||||
return localPart, domainPart, nil
|
||||
}
|
||||
|
||||
func ExtractNormalizedEmailLocalPart(email string) (string, error) {
|
||||
localPart, _, err := SplitEmailDomain(email)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if localPart == "" {
|
||||
return "", errors.New("email local-part is empty")
|
||||
}
|
||||
return localPart, nil
|
||||
}
|
||||
|
||||
func BuildKoreanNameEmailBase(name string) (string, bool, error) {
|
||||
runes := compactNameRunes(name)
|
||||
if len(runes) < 2 {
|
||||
return "", true, nil
|
||||
}
|
||||
|
||||
surname, ok := hanmacSurnameRomanization[runes[0]]
|
||||
if !ok {
|
||||
return "", true, nil
|
||||
}
|
||||
|
||||
var builder strings.Builder
|
||||
for _, r := range runes[1:] {
|
||||
initial, ok := romanizedHangulInitial(r)
|
||||
if !ok {
|
||||
return "", true, nil
|
||||
}
|
||||
builder.WriteString(initial)
|
||||
}
|
||||
builder.WriteString(surname)
|
||||
return builder.String(), false, nil
|
||||
}
|
||||
|
||||
func MatchesSuggestedNameRule(localPart string, base string) bool {
|
||||
localPart = strings.ToLower(strings.TrimSpace(localPart))
|
||||
base = strings.ToLower(strings.TrimSpace(base))
|
||||
if localPart == "" || base == "" {
|
||||
return false
|
||||
}
|
||||
if localPart == base {
|
||||
return true
|
||||
}
|
||||
if !strings.HasPrefix(localPart, base) {
|
||||
return false
|
||||
}
|
||||
suffix := localPart[len(base):]
|
||||
if suffix == "" {
|
||||
return false
|
||||
}
|
||||
for _, r := range suffix {
|
||||
if r < '0' || r > '9' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func compactNameRunes(name string) []rune {
|
||||
var runes []rune
|
||||
for _, r := range strings.TrimSpace(name) {
|
||||
if unicode.IsSpace(r) {
|
||||
continue
|
||||
}
|
||||
runes = append(runes, r)
|
||||
}
|
||||
return runes
|
||||
}
|
||||
|
||||
func romanizedHangulInitial(r rune) (string, bool) {
|
||||
const hangulBase = 0xAC00
|
||||
const hangulEnd = 0xD7A3
|
||||
if r < hangulBase || r > hangulEnd {
|
||||
return "", false
|
||||
}
|
||||
index := int(r-hangulBase) / 588
|
||||
if index < 0 || index >= len(hanmacInitialRomanization) {
|
||||
return "", false
|
||||
}
|
||||
return hanmacInitialRomanization[index], true
|
||||
}
|
||||
Reference in New Issue
Block a user