Use UTS46 instead of IDNA2003
This commit is contained in:
parent
a0a956ee08
commit
53d467938c
|
@ -62,47 +62,31 @@ public class Jid {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string idna_decode(string src) throws InvalidJidError {
|
private static string idna_decode(string src) throws InvalidJidError {
|
||||||
try {
|
|
||||||
ICU.ErrorCode status = ICU.ErrorCode.ZERO_ERROR;
|
ICU.ErrorCode status = ICU.ErrorCode.ZERO_ERROR;
|
||||||
long src16_length = 0;
|
ICU.IDNAInfo info;
|
||||||
string16 src16 = src.to_utf16(-1, null, out src16_length);
|
char[] dest = new char[src.length * 2];
|
||||||
ICU.Char[] dest16 = new ICU.Char[src16_length];
|
ICU.IDNA.openUTS46(ICU.IDNAOptions.DEFAULT, ref status).nameToUnicodeUTF8(src, -1, dest, out info, ref status);
|
||||||
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) {
|
if (status == ICU.ErrorCode.INVALID_CHAR_FOUND) {
|
||||||
throw new InvalidJidError.INVALID_CHAR("Found invalid character");
|
throw new InvalidJidError.INVALID_CHAR("Found invalid character");
|
||||||
} else if (status != ICU.ErrorCode.ZERO_ERROR) {
|
} else if (status.is_failure() || info.errors > 0) {
|
||||||
throw new InvalidJidError.UNKNOWN(@"Unknown error: $(status.errorName())");
|
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)");
|
|
||||||
}
|
}
|
||||||
|
return (string) dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void idna_verify(string src) throws InvalidJidError {
|
private static void idna_verify(string src) throws InvalidJidError {
|
||||||
try {
|
|
||||||
ICU.ErrorCode status = ICU.ErrorCode.ZERO_ERROR;
|
ICU.ErrorCode status = ICU.ErrorCode.ZERO_ERROR;
|
||||||
long src16_length = 0;
|
ICU.IDNAInfo info;
|
||||||
string16 src16 = src.to_utf16(-1, null, out src16_length);
|
char[] dest = new char[src.length * 2];
|
||||||
ICU.Char[] dest16 = new ICU.Char[256];
|
ICU.IDNA.openUTS46(ICU.IDNAOptions.DEFAULT, ref status).nameToASCII_UTF8(src, -1, dest, out info, ref status);
|
||||||
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) {
|
if (status == ICU.ErrorCode.INVALID_CHAR_FOUND) {
|
||||||
throw new InvalidJidError.INVALID_CHAR("Found invalid character");
|
throw new InvalidJidError.INVALID_CHAR("Found invalid character");
|
||||||
} else if (status != ICU.ErrorCode.ZERO_ERROR) {
|
} else if (status.is_failure() || info.errors > 0) {
|
||||||
throw new InvalidJidError.UNKNOWN(@"Unknown error: $(status.errorName())");
|
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)");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
if (src == null) return src;
|
||||||
try {
|
try {
|
||||||
ICU.ErrorCode status = ICU.ErrorCode.ZERO_ERROR;
|
ICU.ErrorCode status = ICU.ErrorCode.ZERO_ERROR;
|
||||||
|
@ -111,7 +95,7 @@ public class Jid {
|
||||||
string16 src16 = src.to_utf16(-1, null, out src16_length);
|
string16 src16 = src.to_utf16(-1, null, out src16_length);
|
||||||
ICU.Char[] dest16 = new ICU.Char[src16_length * 2];
|
ICU.Char[] dest16 = new ICU.Char[src16_length * 2];
|
||||||
ICU.ParseError error;
|
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) {
|
if (status == ICU.ErrorCode.INVALID_CHAR_FOUND) {
|
||||||
throw new InvalidJidError.INVALID_CHAR("Found invalid character");
|
throw new InvalidJidError.INVALID_CHAR("Found invalid character");
|
||||||
} else if (status != ICU.ErrorCode.ZERO_ERROR) {
|
} else if (status != ICU.ErrorCode.ZERO_ERROR) {
|
||||||
|
|
|
@ -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_domain_with_resource", () => { test_jid_valid("example.com/test"); });
|
||||||
add_test("jid_valid_full", () => { test_jid_valid("test@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_local", () => { test_jid_valid("😅@example.com"); });
|
||||||
add_test("jid_valid_emoji_resource", () => { test_jid_valid("test@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("test@example.com"); });
|
add_test("jid_invalid_bidi_local", () => { test_jid_invalid("test@example.com"); });
|
||||||
add_test("jid_invalid_bidi_resource", () => { test_jid_invalid("test@example.com/test"); });
|
add_test("jid_invalid_bidi_resource", () => { test_jid_invalid("test@example.com/test"); });
|
||||||
add_test("jid_invalid_bidi_domain", () => { test_jid_invalid("test@example.com"); });
|
add_test("jid_invalid_bidi_domain", () => { test_jid_invalid("test@example.com"); });
|
||||||
|
@ -43,7 +43,7 @@ class JidTest : Gee.TestCase {
|
||||||
try {
|
try {
|
||||||
new Jid(jid);
|
new Jid(jid);
|
||||||
} catch (Error e) {
|
} catch (Error e) {
|
||||||
fail_if_reached();
|
fail_if_reached(@"Throws $(e.message)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,10 @@ enum ErrorCode {
|
||||||
;
|
;
|
||||||
[CCode (cname = "u_errorName")]
|
[CCode (cname = "u_errorName")]
|
||||||
public unowned string 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")]
|
[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")]
|
[CCode (cname = "UIDNA", cprefix = "uidna_", free_function = "uidna_close", cheader_filename = "unicode/uidna.h")]
|
||||||
[Compact]
|
[Compact]
|
||||||
class IDNA {
|
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 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 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_")]
|
[CCode (cname = "uint32_t", cprefix = "UIDNA_")]
|
||||||
|
|
Loading…
Reference in a new issue