2023-05-29 19:24:57 +00:00
|
|
|
import 'dart:convert';
|
|
|
|
import 'dart:typed_data';
|
|
|
|
|
2023-07-05 22:48:06 +00:00
|
|
|
import 'package:equatable/equatable.dart';
|
|
|
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
|
|
|
2023-05-29 19:24:57 +00:00
|
|
|
String base64UrlNoPadEncode(List<int> bytes) {
|
|
|
|
var x = base64Url.encode(bytes);
|
|
|
|
while (x.endsWith('=')) {
|
|
|
|
x = x.substring(0, x.length - 1);
|
|
|
|
}
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
Uint8List base64UrlNoPadDecode(String source) {
|
2023-10-08 00:33:54 +00:00
|
|
|
source = base64Url.normalize(source);
|
|
|
|
return base64Url.decode(source);
|
2023-05-29 19:24:57 +00:00
|
|
|
}
|
|
|
|
|
2023-10-08 00:33:54 +00:00
|
|
|
Uint8List base64UrlNoPadDecodeDynamic(dynamic source) =>
|
|
|
|
base64UrlNoPadDecode(source as String);
|
2023-05-29 19:24:57 +00:00
|
|
|
|
2023-07-06 03:53:08 +00:00
|
|
|
class Uint8ListJsonConverter implements JsonConverter<Uint8List, String> {
|
|
|
|
const Uint8ListJsonConverter();
|
|
|
|
|
|
|
|
@override
|
2023-07-25 05:04:22 +00:00
|
|
|
Uint8List fromJson(dynamic json) => base64UrlNoPadDecode(json as String);
|
2023-07-06 03:53:08 +00:00
|
|
|
@override
|
|
|
|
String toJson(Uint8List data) => base64UrlNoPadEncode(data);
|
|
|
|
}
|
|
|
|
|
2023-07-05 22:48:06 +00:00
|
|
|
@immutable
|
|
|
|
abstract class EncodedString extends Equatable {
|
2023-07-26 18:20:17 +00:00
|
|
|
const EncodedString(String s) : contents = s;
|
2023-07-05 22:48:06 +00:00
|
|
|
final String contents;
|
|
|
|
@override
|
|
|
|
List<Object> get props => [contents];
|
2023-05-29 19:24:57 +00:00
|
|
|
|
2023-07-26 18:20:17 +00:00
|
|
|
Uint8List decode() => base64UrlNoPadDecode(contents);
|
2023-05-29 19:24:57 +00:00
|
|
|
|
|
|
|
@override
|
2023-07-05 22:48:06 +00:00
|
|
|
String toString() => contents;
|
2023-05-29 19:24:57 +00:00
|
|
|
|
2023-07-13 01:28:00 +00:00
|
|
|
static T fromBytes<T extends EncodedString>(Uint8List bytes) {
|
|
|
|
switch (T) {
|
|
|
|
case FixedEncodedString32:
|
|
|
|
return FixedEncodedString32.fromBytes(bytes) as T;
|
|
|
|
case FixedEncodedString43:
|
|
|
|
return FixedEncodedString43.fromBytes(bytes) as T;
|
|
|
|
case FixedEncodedString86:
|
|
|
|
return FixedEncodedString86.fromBytes(bytes) as T;
|
|
|
|
default:
|
|
|
|
throw UnimplementedError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-29 19:24:57 +00:00
|
|
|
static T fromString<T extends EncodedString>(String s) {
|
|
|
|
switch (T) {
|
|
|
|
case FixedEncodedString32:
|
2023-07-05 22:48:06 +00:00
|
|
|
return FixedEncodedString32.fromString(s) as T;
|
2023-05-29 19:24:57 +00:00
|
|
|
case FixedEncodedString43:
|
2023-07-05 22:48:06 +00:00
|
|
|
return FixedEncodedString43.fromString(s) as T;
|
2023-05-29 19:24:57 +00:00
|
|
|
case FixedEncodedString86:
|
2023-07-05 22:48:06 +00:00
|
|
|
return FixedEncodedString86.fromString(s) as T;
|
2023-05-29 19:24:57 +00:00
|
|
|
default:
|
|
|
|
throw UnimplementedError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-05 22:48:06 +00:00
|
|
|
@immutable
|
2023-05-29 19:24:57 +00:00
|
|
|
class FixedEncodedString32 extends EncodedString {
|
2023-07-13 01:28:00 +00:00
|
|
|
factory FixedEncodedString32.fromBytes(Uint8List bytes) {
|
|
|
|
if (bytes.length != decodedLength()) {
|
2023-07-26 18:20:17 +00:00
|
|
|
throw Exception('length ${bytes.length} should be ${decodedLength()}');
|
2023-07-13 01:28:00 +00:00
|
|
|
}
|
|
|
|
return FixedEncodedString32._(base64UrlNoPadEncode(bytes));
|
|
|
|
}
|
|
|
|
|
2023-07-05 22:48:06 +00:00
|
|
|
factory FixedEncodedString32.fromString(String s) {
|
2023-07-26 18:20:17 +00:00
|
|
|
final d = base64UrlNoPadDecode(s);
|
2023-07-05 22:48:06 +00:00
|
|
|
if (d.length != decodedLength()) {
|
2023-07-26 18:20:17 +00:00
|
|
|
throw Exception('length ${s.length} should be ${encodedLength()}');
|
2023-07-05 22:48:06 +00:00
|
|
|
}
|
|
|
|
return FixedEncodedString32._(s);
|
2023-05-29 19:24:57 +00:00
|
|
|
}
|
2023-07-05 22:48:06 +00:00
|
|
|
factory FixedEncodedString32.fromJson(dynamic json) =>
|
|
|
|
FixedEncodedString32.fromString(json as String);
|
2023-07-26 18:20:17 +00:00
|
|
|
const FixedEncodedString32._(super.s);
|
|
|
|
static int encodedLength() => 32;
|
|
|
|
|
|
|
|
static int decodedLength() => 24;
|
|
|
|
|
|
|
|
String toJson() => toString();
|
2023-05-29 19:24:57 +00:00
|
|
|
}
|
|
|
|
|
2023-07-05 22:48:06 +00:00
|
|
|
@immutable
|
2023-05-29 19:24:57 +00:00
|
|
|
class FixedEncodedString43 extends EncodedString {
|
2023-07-13 01:28:00 +00:00
|
|
|
factory FixedEncodedString43.fromBytes(Uint8List bytes) {
|
|
|
|
if (bytes.length != decodedLength()) {
|
2023-07-26 18:20:17 +00:00
|
|
|
throw Exception('length ${bytes.length} should be ${decodedLength()}');
|
2023-07-13 01:28:00 +00:00
|
|
|
}
|
|
|
|
return FixedEncodedString43._(base64UrlNoPadEncode(bytes));
|
|
|
|
}
|
|
|
|
|
2023-07-05 22:48:06 +00:00
|
|
|
factory FixedEncodedString43.fromString(String s) {
|
2023-07-26 18:20:17 +00:00
|
|
|
final d = base64UrlNoPadDecode(s);
|
2023-07-05 22:48:06 +00:00
|
|
|
if (d.length != decodedLength()) {
|
2023-07-26 18:20:17 +00:00
|
|
|
throw Exception('length ${s.length} should be ${encodedLength()}');
|
2023-07-05 22:48:06 +00:00
|
|
|
}
|
|
|
|
return FixedEncodedString43._(s);
|
2023-05-29 19:24:57 +00:00
|
|
|
}
|
2023-07-05 22:48:06 +00:00
|
|
|
factory FixedEncodedString43.fromJson(dynamic json) =>
|
|
|
|
FixedEncodedString43.fromString(json as String);
|
2023-07-26 18:20:17 +00:00
|
|
|
const FixedEncodedString43._(super.s);
|
|
|
|
static int encodedLength() => 43;
|
|
|
|
|
|
|
|
static int decodedLength() => 32;
|
|
|
|
|
|
|
|
String toJson() => toString();
|
2023-05-29 19:24:57 +00:00
|
|
|
}
|
|
|
|
|
2023-07-05 22:48:06 +00:00
|
|
|
@immutable
|
2023-05-29 19:24:57 +00:00
|
|
|
class FixedEncodedString86 extends EncodedString {
|
2023-07-13 01:28:00 +00:00
|
|
|
factory FixedEncodedString86.fromBytes(Uint8List bytes) {
|
|
|
|
if (bytes.length != decodedLength()) {
|
2023-07-26 18:20:17 +00:00
|
|
|
throw Exception('length ${bytes.length} should be ${decodedLength()}');
|
2023-07-13 01:28:00 +00:00
|
|
|
}
|
|
|
|
return FixedEncodedString86._(base64UrlNoPadEncode(bytes));
|
|
|
|
}
|
|
|
|
|
2023-07-05 22:48:06 +00:00
|
|
|
factory FixedEncodedString86.fromString(String s) {
|
2023-07-26 18:20:17 +00:00
|
|
|
final d = base64UrlNoPadDecode(s);
|
2023-07-05 22:48:06 +00:00
|
|
|
if (d.length != decodedLength()) {
|
2023-07-26 18:20:17 +00:00
|
|
|
throw Exception('length ${s.length} should be ${encodedLength()}');
|
2023-07-05 22:48:06 +00:00
|
|
|
}
|
|
|
|
return FixedEncodedString86._(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
factory FixedEncodedString86.fromJson(dynamic json) =>
|
|
|
|
FixedEncodedString86.fromString(json as String);
|
2023-07-26 18:20:17 +00:00
|
|
|
const FixedEncodedString86._(super.s);
|
|
|
|
static int encodedLength() => 86;
|
|
|
|
|
|
|
|
static int decodedLength() => 64;
|
|
|
|
|
|
|
|
String toJson() => toString();
|
2023-05-29 19:24:57 +00:00
|
|
|
}
|