From f5477717aec34590bee82298db3a64800bb14877 Mon Sep 17 00:00:00 2001 From: Greg Price Date: Wed, 4 Oct 2023 17:09:05 -0700 Subject: [PATCH] api: Fix usage of int.parse that implicitly accepts hexadecimal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling just `int.parse(s)`, without a `radix:` argument, invokes a special behavior where `int.parse` not only accepts decimal strings like "42", but also hexadecimal strings like "0x2a". That's a bit unexpected. In any case it's definitely not something we want when interpreting any part of the Zulip API. Fix the one place we had this in our own code. There remain two places it appears in the code generated by `json_serializable`; mark those with TODO comments. It'd be nice to fix those too, but realistically this quirk is unlikely to ever cause a problem, so it's not worth a lot of effort to resolve. (Note that this doesn't affect the bulk of places we have an int in the API types, because most of those are handled by jsonDecode before the `json_serializable`-generated code ever sees them. It only affects the keys of `Map` structures.) It looks like there's no existing thread in the `json_serializable` tracker for this issue. The most closely related is from where the handling of `Map` types was added in the first place: https://github.com/google/json_serializable.dart/issues/434 --- lib/api/model/events.dart | 1 + lib/api/model/model.dart | 3 +++ lib/api/model/narrow.dart | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/api/model/events.dart b/lib/api/model/events.dart index e1e8d92bbd..86ba97f27f 100644 --- a/lib/api/model/events.dart +++ b/lib/api/model/events.dart @@ -503,6 +503,7 @@ class UpdateMessageFlagsRemoveEvent extends UpdateMessageFlagsEvent { String get op => 'remove'; // final bool all; // deprecated, ignore + // TODO(json_serializable): keys use plain `int.parse`, permitting hexadecimal final Map? messageDetails; UpdateMessageFlagsRemoveEvent({ diff --git a/lib/api/model/model.dart b/lib/api/model/model.dart index 33cb830531..6cf4a06f01 100644 --- a/lib/api/model/model.dart +++ b/lib/api/model/model.dart @@ -134,10 +134,13 @@ class User { String timezone; String? avatarUrl; // TODO distinguish null from missing https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/flutter.3A.20omitted.20vs.2E.20null.20in.20JSON/near/1551759 int avatarVersion; + // null for bots, which don't have custom profile fields. // If null for a non-bot, equivalent to `{}` (null just written for efficiency.) + // TODO(json_serializable): keys use plain `int.parse`, permitting hexadecimal @JsonKey(readValue: _readProfileData) Map? profileData; + @JsonKey(readValue: _readIsSystemBot) bool? isSystemBot; // TODO(server-5) diff --git a/lib/api/model/narrow.dart b/lib/api/model/narrow.dart index 18e7fd4d56..438e0939f8 100644 --- a/lib/api/model/narrow.dart +++ b/lib/api/model/narrow.dart @@ -110,7 +110,7 @@ class ApiNarrowMessageId extends ApiNarrowElement { ApiNarrowMessageId(int operand, {super.negated}) : operand = operand.toString(); factory ApiNarrowMessageId.fromJson(Map json) => ApiNarrowMessageId( - int.parse(json['operand'] as String), + int.parse(json['operand'] as String, radix: 10), negated: json['negated'] as bool? ?? false, ); }