Skip to content

Commit eab5f7a

Browse files
authored
Merge pull request #88 from jonbarrow/feat/updated-profanity-check
Updated NAS profanity check endpoint
2 parents 70950e9 + ca8c9f1 commit eab5f7a

File tree

1 file changed

+85
-13
lines changed

1 file changed

+85
-13
lines changed

nas/auth.go

Lines changed: 85 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -99,24 +99,20 @@ func handleAuthRequest(moduleName string, w http.ResponseWriter, r *http.Request
9999
switch strings.ToLower(action) {
100100
case "acctcreate":
101101
reply = acctcreate()
102-
break
103102

104103
case "login":
105104
isLocalhost := strings.HasPrefix(r.RemoteAddr, "127.0.0.1:") || strings.HasPrefix(r.RemoteAddr, "[::1]:")
106105
reply = login(moduleName, fields, isLocalhost)
107-
break
108106

109107
case "svcloc":
110108
reply = svcloc(fields)
111-
break
112109

113110
default:
114111
logging.Error(moduleName, "Unknown action:", aurora.Cyan(action))
115112
reply = map[string]string{
116113
"retry": "0",
117114
"returncd": "109",
118115
}
119-
break
120116
}
121117
} else if r.URL.String() == "/pr" {
122118
words, ok := fields["words"]
@@ -126,7 +122,7 @@ func handleAuthRequest(moduleName string, w http.ResponseWriter, r *http.Request
126122
return
127123
}
128124

129-
reply = handleProfanity(fields)
125+
reply = handleProfanity(r.PostForm, unitcd)
130126
} else if r.URL.String() == "/download" {
131127
action, ok := fields["action"]
132128
if !ok || action == "" {
@@ -145,15 +141,13 @@ func handleAuthRequest(moduleName string, w http.ResponseWriter, r *http.Request
145141
switch strings.ToLower(action) {
146142
case "count":
147143
response = []byte(dlsCount(fields))
148-
break
149144

150145
default:
151146
logging.Error(moduleName, "Unknown action:", aurora.Cyan(action))
152147
reply = map[string]string{
153148
"retry": "0",
154149
"returncd": "109",
155150
}
156-
break
157151
}
158152

159153
w.Header().Set("X-DLS-Host", "http://127.0.0.1/")
@@ -349,25 +343,90 @@ func svcloc(fields map[string]string) map[string]string {
349343
default:
350344
param["servicetoken"] = authToken
351345
param["svchost"] = "n/a"
352-
break
353346

354347
case "9000":
355348
param["token"] = authToken
356349
param["svchost"] = "dls1.nintendowifi.net"
357-
break
358350

359351
case "9001":
360352
param["servicetoken"] = authToken
361353
param["svchost"] = "dls1.nintendowifi.net"
362-
break
363354
}
364355

365356
return param
366357
}
367358

368-
func handleProfanity(fields map[string]string) map[string]string {
359+
func handleProfanity(form url.Values, unitcd string) map[string]string {
360+
var wordsEncoding string
361+
var wordsDefaultEncoding string
362+
var wordsBytes []byte
363+
var words string
364+
var wordsRegion string
369365
var prwords string
370-
for _, word := range strings.Split(fields["words"], "\t") {
366+
367+
if unitcd == "0" {
368+
wordsEncoding = "UTF-16LE"
369+
wordsDefaultEncoding = "UTF-16LE"
370+
} else {
371+
wordsEncoding = "UTF-16BE"
372+
wordsDefaultEncoding = "UTF-16BE"
373+
}
374+
375+
if wencValues, ok := form["wenc"]; ok {
376+
// It's okay for this to error, the real server
377+
// just falls back to the default encoding in
378+
// this case even if it cant properly handle it
379+
wencDecoded, err := common.Base64DwcEncoding.DecodeString(wencValues[0])
380+
if err == nil {
381+
wordsEncoding = string(wencDecoded)
382+
}
383+
}
384+
385+
if wordsEncoding != "UTF-8" && wordsEncoding != "UTF-16LE" && wordsEncoding != "UTF-16BE" {
386+
wordsEncoding = wordsDefaultEncoding
387+
}
388+
389+
// It's okay for this to not exist/be valid, the real
390+
// server will just treat the missing input as a single
391+
// non-profane word
392+
if wordsValues, ok := form["words"]; ok {
393+
wordsDecoded, err := common.Base64DwcEncoding.DecodeString(wordsValues[0])
394+
if err == nil {
395+
wordsBytes = wordsDecoded
396+
}
397+
}
398+
399+
// This field is entirely optional, unsure what
400+
// specifically it does. Adds extra data to the
401+
// reply, probably used for handling the word
402+
// list differently for different regions?
403+
if wordsRegionValues, ok := form["wregion"]; ok {
404+
wordsRegionDecoded, err := common.Base64DwcEncoding.DecodeString(wordsRegionValues[0])
405+
if err == nil {
406+
wordsRegion = string(wordsRegionDecoded)
407+
}
408+
}
409+
410+
if wordsEncoding == "UTF-8" {
411+
words = string(wordsBytes)
412+
} else {
413+
var utf16String []uint16
414+
if unitcd == "0" {
415+
for i := 0; i < len(wordsBytes)/2; i++ {
416+
utf16String = append(utf16String, binary.LittleEndian.Uint16(wordsBytes[i*2:i*2+2]))
417+
}
418+
} else {
419+
for i := 0; i < len(wordsBytes)/2; i++ {
420+
utf16String = append(utf16String, binary.BigEndian.Uint16(wordsBytes[i*2:i*2+2]))
421+
}
422+
}
423+
424+
words = string(utf16.Decode(utf16String))
425+
}
426+
427+
// TODO - Handle wtype? Unsure what this field does, seems to always be an emtpy string
428+
429+
for _, word := range strings.Split(words, "\t") {
371430
if isBadWord, _ := IsBadWord(word); isBadWord {
372431
prwords += "1"
373432
} else {
@@ -382,10 +441,23 @@ func handleProfanity(fields map[string]string) map[string]string {
382441
returncd = "000"
383442
}
384443

385-
return map[string]string{
444+
reply := map[string]string{
386445
"returncd": returncd,
387446
"prwords": prwords,
388447
}
448+
449+
// Only known value of this field that works this way
450+
if wordsRegion == "A" {
451+
// TODO - The real server seems to handle the input words differently per region? These values are supposed to differ from prwords
452+
reply["prwordsA"] = prwords
453+
reply["prwordsC"] = prwords
454+
reply["prwordsE"] = prwords
455+
reply["prwordsJ"] = prwords
456+
reply["prwordsK"] = prwords
457+
reply["prwordsP"] = prwords
458+
}
459+
460+
return reply
389461
}
390462

391463
func dlsCount(fields map[string]string) string {

0 commit comments

Comments
 (0)