@@ -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
391463func dlsCount (fields map [string ]string ) string {
0 commit comments