aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin W <git@larma.de>2019-12-23 04:01:25 +0100
committerMarvin W <git@larma.de>2019-12-23 16:58:55 +0100
commit53d467938cb1d3fb73bab3707319bc740eda9b10 (patch)
tree2583b6f7abaae2a87a619ba24fa4adc1d1f5f8ae
parenta0a956ee0878d24bd06be7f5d75dc4ccd4e7901d (diff)
downloaddino-53d467938cb1d3fb73bab3707319bc740eda9b10.tar.gz
dino-53d467938cb1d3fb73bab3707319bc740eda9b10.zip
Use UTS46 instead of IDNA2003
-rw-r--r--xmpp-vala/src/module/jid.vala54
-rw-r--r--xmpp-vala/tests/jid.vala6
-rw-r--r--xmpp-vala/vapi/icu-uc.vapi16
3 files changed, 38 insertions, 38 deletions
diff --git a/xmpp-vala/src/module/jid.vala b/xmpp-vala/src/module/jid.vala
index 569be54f..f8d09e7e 100644
--- a/xmpp-vala/src/module/jid.vala
+++ b/xmpp-vala/src/module/jid.vala
@@ -62,47 +62,31 @@ public class Jid {
}
private static string idna_decode(string src) throws InvalidJidError {
- try {
- ICU.ErrorCode status = ICU.ErrorCode.ZERO_ERROR;
- long src16_length = 0;
- string16 src16 = src.to_utf16(-1, null, out src16_length);
- ICU.Char[] dest16 = new ICU.Char[src16_length];
- ICU.ParseError error;
- long dest16_length = ICU.IDNA.IDNToUnicode(src16, (int32) src16_length, dest16, dest16.length, ICU.IDNAOptions.DEFAULT, out error, ref status);
- if (status == ICU.ErrorCode.INVALID_CHAR_FOUND) {
- throw new InvalidJidError.INVALID_CHAR("Found invalid character");
- } else if (status != ICU.ErrorCode.ZERO_ERROR) {
- throw new InvalidJidError.UNKNOWN(@"Unknown error: $(status.errorName())");
- } else if (dest16_length < 0) {
- throw new InvalidJidError.UNKNOWN("Unknown error");
- }
- return ((string16) dest16).to_utf8(dest16_length, null, null);
- } catch (ConvertError e) {
- throw new InvalidJidError.INVALID_CHAR(@"Conversion error: $(e.message)");
+ ICU.ErrorCode status = ICU.ErrorCode.ZERO_ERROR;
+ ICU.IDNAInfo info;
+ char[] dest = new char[src.length * 2];
+ ICU.IDNA.openUTS46(ICU.IDNAOptions.DEFAULT, ref status).nameToUnicodeUTF8(src, -1, dest, out info, ref status);
+ if (status == ICU.ErrorCode.INVALID_CHAR_FOUND) {
+ throw new InvalidJidError.INVALID_CHAR("Found invalid character");
+ } else if (status.is_failure() || info.errors > 0) {
+ throw new InvalidJidError.UNKNOWN(@"Unknown error: $(status.errorName())");
}
+ return (string) dest;
}
private static void idna_verify(string src) throws InvalidJidError {
- try {
- ICU.ErrorCode status = ICU.ErrorCode.ZERO_ERROR;
- long src16_length = 0;
- string16 src16 = src.to_utf16(-1, null, out src16_length);
- ICU.Char[] dest16 = new ICU.Char[256];
- ICU.ParseError error;
- long dest16_length = ICU.IDNA.IDNToASCII(src16, (int32) src16_length, dest16, dest16.length, ICU.IDNAOptions.DEFAULT, out error, ref status);
- if (status == ICU.ErrorCode.INVALID_CHAR_FOUND) {
- throw new InvalidJidError.INVALID_CHAR("Found invalid character");
- } else if (status != ICU.ErrorCode.ZERO_ERROR) {
- throw new InvalidJidError.UNKNOWN(@"Unknown error: $(status.errorName())");
- } else if (dest16_length < 0) {
- throw new InvalidJidError.UNKNOWN("Unknown error");
- }
- } catch (ConvertError e) {
- throw new InvalidJidError.INVALID_CHAR(@"Conversion error: $(e.message)");
+ ICU.ErrorCode status = ICU.ErrorCode.ZERO_ERROR;
+ ICU.IDNAInfo info;
+ char[] dest = new char[src.length * 2];
+ ICU.IDNA.openUTS46(ICU.IDNAOptions.DEFAULT, ref status).nameToASCII_UTF8(src, -1, dest, out info, ref status);
+ if (status == ICU.ErrorCode.INVALID_CHAR_FOUND) {
+ throw new InvalidJidError.INVALID_CHAR("Found invalid character");
+ } else if (status.is_failure() || info.errors > 0) {
+ throw new InvalidJidError.UNKNOWN(@"Unknown error: $(status.errorName())");
}
}
- private static string? prepare(string? src, ICU.PrepType type) throws InvalidJidError {
+ private static string? prepare(string? src, ICU.PrepType type, bool strict = false) throws InvalidJidError {
if (src == null) return src;
try {
ICU.ErrorCode status = ICU.ErrorCode.ZERO_ERROR;
@@ -111,7 +95,7 @@ public class Jid {
string16 src16 = src.to_utf16(-1, null, out src16_length);
ICU.Char[] dest16 = new ICU.Char[src16_length * 2];
ICU.ParseError error;
- long dest16_length = profile.prepare((ICU.Char*) src16, (int32) src16_length, dest16, dest16.length, ICU.PrepOptions.ALLOW_UNASSIGNED, out error, ref status);
+ long dest16_length = profile.prepare((ICU.Char*) src16, (int32) src16_length, dest16, dest16.length, strict ? ICU.PrepOptions.DEFAULT : ICU.PrepOptions.ALLOW_UNASSIGNED, out error, ref status);
if (status == ICU.ErrorCode.INVALID_CHAR_FOUND) {
throw new InvalidJidError.INVALID_CHAR("Found invalid character");
} else if (status != ICU.ErrorCode.ZERO_ERROR) {
diff --git a/xmpp-vala/tests/jid.vala b/xmpp-vala/tests/jid.vala
index 8928dc97..75eb38ce 100644
--- a/xmpp-vala/tests/jid.vala
+++ b/xmpp-vala/tests/jid.vala
@@ -9,11 +9,11 @@ class JidTest : Gee.TestCase {
add_test("jid_valid_domain_with_resource", () => { test_jid_valid("example.com/test"); });
add_test("jid_valid_full", () => { test_jid_valid("test@example.com/test"); });
- // Should those actually be valid?
+ // These should not be valid in "strict-mode"
add_test("jid_valid_emoji_local", () => { test_jid_valid("😅@example.com"); });
add_test("jid_valid_emoji_resource", () => { test_jid_valid("test@example.com/😅"); });
+ add_test("jid_valid_emoji_domain", () => { test_jid_valid("test@😅.com"); });
- add_test("jid_invalid_emoji_domain", () => { test_jid_invalid("test@😅.com"); });
add_test("jid_invalid_bidi_local", () => { test_jid_invalid("te‏st@example.com"); });
add_test("jid_invalid_bidi_resource", () => { test_jid_invalid("test@example.com/te‏st"); });
add_test("jid_invalid_bidi_domain", () => { test_jid_invalid("test@exa‏mple.com"); });
@@ -43,7 +43,7 @@ class JidTest : Gee.TestCase {
try {
new Jid(jid);
} catch (Error e) {
- fail_if_reached();
+ fail_if_reached(@"Throws $(e.message)");
}
}
diff --git a/xmpp-vala/vapi/icu-uc.vapi b/xmpp-vala/vapi/icu-uc.vapi
index 14764440..328523d1 100644
--- a/xmpp-vala/vapi/icu-uc.vapi
+++ b/xmpp-vala/vapi/icu-uc.vapi
@@ -15,6 +15,10 @@ enum ErrorCode {
;
[CCode (cname = "u_errorName")]
public unowned string errorName();
+ [CCode (cname = "U_SUCCESS")]
+ public bool is_success();
+ [CCode (cname = "U_FAILURE")]
+ public bool is_failure();
}
[CCode (cname = "UErrorCode", cprefix = "U_", cheader_filename = "unicode/parseerr.h")]
@@ -42,8 +46,20 @@ enum PrepOptions {
[CCode (cname = "UIDNA", cprefix = "uidna_", free_function = "uidna_close", cheader_filename = "unicode/uidna.h")]
[Compact]
class IDNA {
+ public static IDNA openUTS46(IDNAOptions options, ref ErrorCode status);
public static int32 IDNToUnicode(Char* src, int32 src_length, Char* dest, int32 dest_capacity, IDNAOptions options, out ParseError parse_error, ref ErrorCode status);
public static int32 IDNToASCII(Char* src, int32 src_length, Char* dest, int32 dest_capacity, IDNAOptions options, out ParseError parse_error, ref ErrorCode status);
+ public int32 nameToUnicode(Char* src, int32 src_length, Char* dest, int32 dest_capacity, out IDNAInfo info, ref ErrorCode status);
+ public int32 nameToASCII(Char* src, int32 src_length, Char* dest, int32 dest_capacity, out IDNAInfo info, ref ErrorCode status);
+ public int32 nameToASCII_UTF8(string name, int32 name_length, char[] dest, out IDNAInfo info, ref ErrorCode status);
+ public int32 nameToUnicodeUTF8(string name, int32 name_length, char[] dest, out IDNAInfo info, ref ErrorCode status);
+}
+
+[CCode (cname = "UIDNAInfo", default_value = "UIDNA_INFO_INITIALIZER", has_type_id = false, cheader_filename = "unicode/uidna.h")]
+struct IDNAInfo {
+ public static IDNAInfo INITIAL;
+ public uint32 errors;
+ public bool isTransitionalDifferent;
}
[CCode (cname = "uint32_t", cprefix = "UIDNA_")]