1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef nsIDNService_h__
7 #define nsIDNService_h__
8 
9 #include "nsIIDNService.h"
10 #include "nsCOMPtr.h"
11 #include "nsIObserver.h"
12 #include "nsUnicodeScriptCodes.h"
13 #include "nsWeakReference.h"
14 
15 #ifdef IDNA2008
16 #include "unicode/uidna.h"
17 #else
18 #include "nsIUnicodeNormalizer.h"
19 #include "nsIDNKitInterface.h"
20 #endif
21 
22 #include "nsString.h"
23 
24 class nsIPrefBranch;
25 
26 //-----------------------------------------------------------------------------
27 // nsIDNService
28 //-----------------------------------------------------------------------------
29 
30 class nsIDNService final : public nsIIDNService,
31                            public nsIObserver,
32                            public nsSupportsWeakReference
33 {
34 public:
35   NS_DECL_THREADSAFE_ISUPPORTS
36   NS_DECL_NSIIDNSERVICE
37   NS_DECL_NSIOBSERVER
38 
39   nsIDNService();
40 
41   nsresult Init();
42 
43 protected:
44   virtual ~nsIDNService();
45 
46 private:
47   enum stringPrepFlag {
48     eStringPrepForDNS,
49     eStringPrepForUI,
50     eStringPrepIgnoreErrors
51   };
52 
53   /**
54    * Convert the following characters that must be recognized as label
55    *  separators per RFC 3490 to ASCII full stop characters
56    *
57    * U+3002 (ideographic full stop)
58    * U+FF0E (fullwidth full stop)
59    * U+FF61 (halfwidth ideographic full stop)
60    */
61   void normalizeFullStops(nsAString& s);
62 
63   /**
64    * Convert and encode a DNS label in ACE/punycode.
65    * @param flag
66    *        if eStringPrepIgnoreErrors, all non-ASCII labels are
67    *           converted to punycode.
68    *        if eStringPrepForUI, only labels that are considered safe
69    *           for display are converted.
70    *           @see isLabelSafe
71    *        if eStringPrepForDNS and stringPrep finds an illegal
72    *           character, returns NS_FAILURE and out is empty
73    */
74   nsresult stringPrepAndACE(const nsAString& in, nsACString& out,
75                             stringPrepFlag flag);
76 
77   /**
78    * Convert a DNS label using the stringprep profile defined in RFC 3454
79    */
80   nsresult stringPrep(const nsAString& in, nsAString& out, stringPrepFlag flag);
81 
82   /**
83    * Decode an ACE-encoded DNS label to UTF-8
84    *
85    * @param flag
86    *        if eStringPrepForUI and the label is not considered safe to
87    *           display, the output is the same as the input
88    *        @see isLabelSafe
89    */
90   nsresult decodeACE(const nsACString& in, nsACString& out,
91                      stringPrepFlag flag);
92 
93   /**
94    * Convert complete domain names between UTF8 and ACE and vice versa
95    *
96    * @param flag is passed to decodeACE or stringPrepAndACE for each
97    *  label individually, so the output may contain some labels in
98    *  punycode and some in UTF-8
99    */
100   nsresult UTF8toACE(const nsACString& input, nsACString& ace,
101                      stringPrepFlag flag);
102   nsresult ACEtoUTF8(const nsACString& input, nsACString& _retval,
103                      stringPrepFlag flag);
104 
105   bool isInWhitelist(const nsACString &host);
106   void prefsChanged(nsIPrefBranch *prefBranch, const char16_t *pref);
107 
108   /**
109    * Determine whether a label is considered safe to display to the user
110    * according to the algorithm defined in UTR 39 and the profile
111    * selected in mRestrictionProfile.
112    *
113    * For the ASCII-only profile, returns false for all labels containing
114    * non-ASCII characters.
115    *
116    * For the other profiles, returns false for labels containing any of
117    * the following:
118    *
119    *  Characters in scripts other than the "recommended scripts" and
120    *   "aspirational scripts" defined in
121    *   http://www.unicode.org/reports/tr31/#Table_Recommended_Scripts
122    *   and http://www.unicode.org/reports/tr31/#Aspirational_Use_Scripts
123    *  This includes codepoints that are not defined as Unicode
124    *   characters
125    *
126    *  Illegal combinations of scripts (@see illegalScriptCombo)
127    *
128    *  Numbers from more than one different numbering system
129    *
130    *  Sequences of the same non-spacing mark
131    *
132    *  Both simplified-only and traditional-only Chinese characters
133    *   XXX this test was disabled by bug 857481
134    */
135   bool isLabelSafe(const nsAString &label);
136 
137   /**
138    * Determine whether a combination of scripts in a single label is
139    * permitted according to the algorithm defined in UTR 39 and the
140    * profile selected in mRestrictionProfile.
141    *
142    * For the "Highly restrictive" profile, all characters in each
143    * identifier must be from a single script, or from the combinations:
144    *  Latin + Han + Hiragana + Katakana;
145    *  Latin + Han + Bopomofo; or
146    *  Latin + Han + Hangul
147    *
148    * For the "Moderately restrictive" profile, Latin is also allowed
149    *  with other scripts except Cyrillic and Greek
150    */
151   bool illegalScriptCombo(mozilla::unicode::Script script,
152                           int32_t& savedScript);
153 
154 #ifdef IDNA2008
155   /**
156    * Convert a DNS label from ASCII to Unicode using IDNA2008
157    */
158   nsresult IDNA2008ToUnicode(const nsACString& input, nsAString& output);
159 
160   /**
161    * Convert a DNS label to a normalized form conforming to IDNA2008
162    */
163   nsresult IDNA2008StringPrep(const nsAString& input, nsAString& output,
164                               stringPrepFlag flag);
165 
166   UIDNA* mIDNA;
167 #else
168   idn_nameprep_t mNamePrepHandle;
169   nsCOMPtr<nsIUnicodeNormalizer> mNormalizer;
170 #endif
171   nsXPIDLString mIDNBlacklist;
172 
173   /**
174    * Flag set by the pref network.IDN_show_punycode. When it is true,
175    * IDNs containing non-ASCII characters are always displayed to the
176    * user in punycode
177    */
178   bool mShowPunycode;
179 
180   /**
181    * Restriction-level Detection profiles defined in UTR 39
182    * http://www.unicode.org/reports/tr39/#Restriction_Level_Detection,
183    * and selected by the pref network.IDN.restriction_profile
184    */
185    enum restrictionProfile {
186     eASCIIOnlyProfile,
187     eHighlyRestrictiveProfile,
188     eModeratelyRestrictiveProfile
189   };
190   restrictionProfile mRestrictionProfile;
191   nsCOMPtr<nsIPrefBranch> mIDNWhitelistPrefBranch;
192   bool mIDNUseWhitelist;
193 };
194 
195 #endif  // nsIDNService_h__
196