mirror of
https://github.com/foss42/apidash.git
synced 2025-12-01 10:17:47 +08:00
feat: implement oauth1
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:apidash/utils/utils.dart';
|
||||||
import 'package:apidash/widgets/widgets.dart';
|
import 'package:apidash/widgets/widgets.dart';
|
||||||
import 'package:apidash_core/apidash_core.dart';
|
import 'package:apidash_core/apidash_core.dart';
|
||||||
import 'package:apidash_design_system/widgets/widgets.dart';
|
import 'package:apidash_design_system/widgets/widgets.dart';
|
||||||
@@ -188,7 +189,13 @@ class _OAuth1FieldsState extends State<OAuth1Fields> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateOAuth1() {
|
void _updateOAuth1() async {
|
||||||
|
final String? credentialsFilePath =
|
||||||
|
await getApplicationSupportDirectoryFilePath(
|
||||||
|
"oauth1_credentials", "json");
|
||||||
|
if (credentialsFilePath == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
widget.updateAuth?.call(
|
widget.updateAuth?.call(
|
||||||
widget.authData?.copyWith(
|
widget.authData?.copyWith(
|
||||||
type: APIAuthType.oauth1,
|
type: APIAuthType.oauth1,
|
||||||
@@ -204,6 +211,7 @@ class _OAuth1FieldsState extends State<OAuth1Fields> {
|
|||||||
timestamp: _timestampController.text.trim(),
|
timestamp: _timestampController.text.trim(),
|
||||||
nonce: _nonceController.text.trim(),
|
nonce: _nonceController.text.trim(),
|
||||||
realm: _realmController.text.trim(),
|
realm: _realmController.text.trim(),
|
||||||
|
credentialsFilePath: credentialsFilePath,
|
||||||
),
|
),
|
||||||
) ??
|
) ??
|
||||||
AuthModel(
|
AuthModel(
|
||||||
@@ -220,6 +228,7 @@ class _OAuth1FieldsState extends State<OAuth1Fields> {
|
|||||||
timestamp: _timestampController.text.trim(),
|
timestamp: _timestampController.text.trim(),
|
||||||
nonce: _nonceController.text.trim(),
|
nonce: _nonceController.text.trim(),
|
||||||
realm: _realmController.text.trim(),
|
realm: _realmController.text.trim(),
|
||||||
|
credentialsFilePath: credentialsFilePath,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ class AuthOAuth1Model with _$AuthOAuth1Model {
|
|||||||
const factory AuthOAuth1Model({
|
const factory AuthOAuth1Model({
|
||||||
required String consumerKey,
|
required String consumerKey,
|
||||||
required String consumerSecret,
|
required String consumerSecret,
|
||||||
|
required String credentialsFilePath,
|
||||||
String? accessToken,
|
String? accessToken,
|
||||||
String? tokenSecret,
|
String? tokenSecret,
|
||||||
@Default("hmacSha1") String signatureMethod,
|
@Default("hmacSha1") String signatureMethod,
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ AuthOAuth1Model _$AuthOAuth1ModelFromJson(Map<String, dynamic> json) {
|
|||||||
mixin _$AuthOAuth1Model {
|
mixin _$AuthOAuth1Model {
|
||||||
String get consumerKey => throw _privateConstructorUsedError;
|
String get consumerKey => throw _privateConstructorUsedError;
|
||||||
String get consumerSecret => throw _privateConstructorUsedError;
|
String get consumerSecret => throw _privateConstructorUsedError;
|
||||||
|
String get credentialsFilePath => throw _privateConstructorUsedError;
|
||||||
String? get accessToken => throw _privateConstructorUsedError;
|
String? get accessToken => throw _privateConstructorUsedError;
|
||||||
String? get tokenSecret => throw _privateConstructorUsedError;
|
String? get tokenSecret => throw _privateConstructorUsedError;
|
||||||
String get signatureMethod => throw _privateConstructorUsedError;
|
String get signatureMethod => throw _privateConstructorUsedError;
|
||||||
@@ -55,6 +56,7 @@ abstract class $AuthOAuth1ModelCopyWith<$Res> {
|
|||||||
$Res call({
|
$Res call({
|
||||||
String consumerKey,
|
String consumerKey,
|
||||||
String consumerSecret,
|
String consumerSecret,
|
||||||
|
String credentialsFilePath,
|
||||||
String? accessToken,
|
String? accessToken,
|
||||||
String? tokenSecret,
|
String? tokenSecret,
|
||||||
String signatureMethod,
|
String signatureMethod,
|
||||||
@@ -86,6 +88,7 @@ class _$AuthOAuth1ModelCopyWithImpl<$Res, $Val extends AuthOAuth1Model>
|
|||||||
$Res call({
|
$Res call({
|
||||||
Object? consumerKey = null,
|
Object? consumerKey = null,
|
||||||
Object? consumerSecret = null,
|
Object? consumerSecret = null,
|
||||||
|
Object? credentialsFilePath = null,
|
||||||
Object? accessToken = freezed,
|
Object? accessToken = freezed,
|
||||||
Object? tokenSecret = freezed,
|
Object? tokenSecret = freezed,
|
||||||
Object? signatureMethod = null,
|
Object? signatureMethod = null,
|
||||||
@@ -108,6 +111,10 @@ class _$AuthOAuth1ModelCopyWithImpl<$Res, $Val extends AuthOAuth1Model>
|
|||||||
? _value.consumerSecret
|
? _value.consumerSecret
|
||||||
: consumerSecret // ignore: cast_nullable_to_non_nullable
|
: consumerSecret // ignore: cast_nullable_to_non_nullable
|
||||||
as String,
|
as String,
|
||||||
|
credentialsFilePath: null == credentialsFilePath
|
||||||
|
? _value.credentialsFilePath
|
||||||
|
: credentialsFilePath // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
accessToken: freezed == accessToken
|
accessToken: freezed == accessToken
|
||||||
? _value.accessToken
|
? _value.accessToken
|
||||||
: accessToken // ignore: cast_nullable_to_non_nullable
|
: accessToken // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -170,6 +177,7 @@ abstract class _$$AuthOAuth1ModelImplCopyWith<$Res>
|
|||||||
$Res call({
|
$Res call({
|
||||||
String consumerKey,
|
String consumerKey,
|
||||||
String consumerSecret,
|
String consumerSecret,
|
||||||
|
String credentialsFilePath,
|
||||||
String? accessToken,
|
String? accessToken,
|
||||||
String? tokenSecret,
|
String? tokenSecret,
|
||||||
String signatureMethod,
|
String signatureMethod,
|
||||||
@@ -200,6 +208,7 @@ class __$$AuthOAuth1ModelImplCopyWithImpl<$Res>
|
|||||||
$Res call({
|
$Res call({
|
||||||
Object? consumerKey = null,
|
Object? consumerKey = null,
|
||||||
Object? consumerSecret = null,
|
Object? consumerSecret = null,
|
||||||
|
Object? credentialsFilePath = null,
|
||||||
Object? accessToken = freezed,
|
Object? accessToken = freezed,
|
||||||
Object? tokenSecret = freezed,
|
Object? tokenSecret = freezed,
|
||||||
Object? signatureMethod = null,
|
Object? signatureMethod = null,
|
||||||
@@ -222,6 +231,10 @@ class __$$AuthOAuth1ModelImplCopyWithImpl<$Res>
|
|||||||
? _value.consumerSecret
|
? _value.consumerSecret
|
||||||
: consumerSecret // ignore: cast_nullable_to_non_nullable
|
: consumerSecret // ignore: cast_nullable_to_non_nullable
|
||||||
as String,
|
as String,
|
||||||
|
credentialsFilePath: null == credentialsFilePath
|
||||||
|
? _value.credentialsFilePath
|
||||||
|
: credentialsFilePath // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
accessToken: freezed == accessToken
|
accessToken: freezed == accessToken
|
||||||
? _value.accessToken
|
? _value.accessToken
|
||||||
: accessToken // ignore: cast_nullable_to_non_nullable
|
: accessToken // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -277,6 +290,7 @@ class _$AuthOAuth1ModelImpl implements _AuthOAuth1Model {
|
|||||||
const _$AuthOAuth1ModelImpl({
|
const _$AuthOAuth1ModelImpl({
|
||||||
required this.consumerKey,
|
required this.consumerKey,
|
||||||
required this.consumerSecret,
|
required this.consumerSecret,
|
||||||
|
required this.credentialsFilePath,
|
||||||
this.accessToken,
|
this.accessToken,
|
||||||
this.tokenSecret,
|
this.tokenSecret,
|
||||||
this.signatureMethod = "hmacSha1",
|
this.signatureMethod = "hmacSha1",
|
||||||
@@ -298,6 +312,8 @@ class _$AuthOAuth1ModelImpl implements _AuthOAuth1Model {
|
|||||||
@override
|
@override
|
||||||
final String consumerSecret;
|
final String consumerSecret;
|
||||||
@override
|
@override
|
||||||
|
final String credentialsFilePath;
|
||||||
|
@override
|
||||||
final String? accessToken;
|
final String? accessToken;
|
||||||
@override
|
@override
|
||||||
final String? tokenSecret;
|
final String? tokenSecret;
|
||||||
@@ -326,7 +342,7 @@ class _$AuthOAuth1ModelImpl implements _AuthOAuth1Model {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'AuthOAuth1Model(consumerKey: $consumerKey, consumerSecret: $consumerSecret, accessToken: $accessToken, tokenSecret: $tokenSecret, signatureMethod: $signatureMethod, parameterLocation: $parameterLocation, version: $version, realm: $realm, callbackUrl: $callbackUrl, verifier: $verifier, nonce: $nonce, timestamp: $timestamp, includeBodyHash: $includeBodyHash)';
|
return 'AuthOAuth1Model(consumerKey: $consumerKey, consumerSecret: $consumerSecret, credentialsFilePath: $credentialsFilePath, accessToken: $accessToken, tokenSecret: $tokenSecret, signatureMethod: $signatureMethod, parameterLocation: $parameterLocation, version: $version, realm: $realm, callbackUrl: $callbackUrl, verifier: $verifier, nonce: $nonce, timestamp: $timestamp, includeBodyHash: $includeBodyHash)';
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -338,6 +354,8 @@ class _$AuthOAuth1ModelImpl implements _AuthOAuth1Model {
|
|||||||
other.consumerKey == consumerKey) &&
|
other.consumerKey == consumerKey) &&
|
||||||
(identical(other.consumerSecret, consumerSecret) ||
|
(identical(other.consumerSecret, consumerSecret) ||
|
||||||
other.consumerSecret == consumerSecret) &&
|
other.consumerSecret == consumerSecret) &&
|
||||||
|
(identical(other.credentialsFilePath, credentialsFilePath) ||
|
||||||
|
other.credentialsFilePath == credentialsFilePath) &&
|
||||||
(identical(other.accessToken, accessToken) ||
|
(identical(other.accessToken, accessToken) ||
|
||||||
other.accessToken == accessToken) &&
|
other.accessToken == accessToken) &&
|
||||||
(identical(other.tokenSecret, tokenSecret) ||
|
(identical(other.tokenSecret, tokenSecret) ||
|
||||||
@@ -365,6 +383,7 @@ class _$AuthOAuth1ModelImpl implements _AuthOAuth1Model {
|
|||||||
runtimeType,
|
runtimeType,
|
||||||
consumerKey,
|
consumerKey,
|
||||||
consumerSecret,
|
consumerSecret,
|
||||||
|
credentialsFilePath,
|
||||||
accessToken,
|
accessToken,
|
||||||
tokenSecret,
|
tokenSecret,
|
||||||
signatureMethod,
|
signatureMethod,
|
||||||
@@ -399,6 +418,7 @@ abstract class _AuthOAuth1Model implements AuthOAuth1Model {
|
|||||||
const factory _AuthOAuth1Model({
|
const factory _AuthOAuth1Model({
|
||||||
required final String consumerKey,
|
required final String consumerKey,
|
||||||
required final String consumerSecret,
|
required final String consumerSecret,
|
||||||
|
required final String credentialsFilePath,
|
||||||
final String? accessToken,
|
final String? accessToken,
|
||||||
final String? tokenSecret,
|
final String? tokenSecret,
|
||||||
final String signatureMethod,
|
final String signatureMethod,
|
||||||
@@ -420,6 +440,8 @@ abstract class _AuthOAuth1Model implements AuthOAuth1Model {
|
|||||||
@override
|
@override
|
||||||
String get consumerSecret;
|
String get consumerSecret;
|
||||||
@override
|
@override
|
||||||
|
String get credentialsFilePath;
|
||||||
|
@override
|
||||||
String? get accessToken;
|
String? get accessToken;
|
||||||
@override
|
@override
|
||||||
String? get tokenSecret;
|
String? get tokenSecret;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ _$AuthOAuth1ModelImpl _$$AuthOAuth1ModelImplFromJson(
|
|||||||
) => _$AuthOAuth1ModelImpl(
|
) => _$AuthOAuth1ModelImpl(
|
||||||
consumerKey: json['consumerKey'] as String,
|
consumerKey: json['consumerKey'] as String,
|
||||||
consumerSecret: json['consumerSecret'] as String,
|
consumerSecret: json['consumerSecret'] as String,
|
||||||
|
credentialsFilePath: json['credentialsFilePath'] as String,
|
||||||
accessToken: json['accessToken'] as String?,
|
accessToken: json['accessToken'] as String?,
|
||||||
tokenSecret: json['tokenSecret'] as String?,
|
tokenSecret: json['tokenSecret'] as String?,
|
||||||
signatureMethod: json['signatureMethod'] as String? ?? "hmacSha1",
|
signatureMethod: json['signatureMethod'] as String? ?? "hmacSha1",
|
||||||
@@ -29,6 +30,7 @@ Map<String, dynamic> _$$AuthOAuth1ModelImplToJson(
|
|||||||
) => <String, dynamic>{
|
) => <String, dynamic>{
|
||||||
'consumerKey': instance.consumerKey,
|
'consumerKey': instance.consumerKey,
|
||||||
'consumerSecret': instance.consumerSecret,
|
'consumerSecret': instance.consumerSecret,
|
||||||
|
'credentialsFilePath': instance.credentialsFilePath,
|
||||||
'accessToken': instance.accessToken,
|
'accessToken': instance.accessToken,
|
||||||
'tokenSecret': instance.tokenSecret,
|
'tokenSecret': instance.tokenSecret,
|
||||||
'signatureMethod': instance.signatureMethod,
|
'signatureMethod': instance.signatureMethod,
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import 'package:better_networking/better_networking.dart';
|
|||||||
import 'package:better_networking/utils/auth/oauth2_utils.dart';
|
import 'package:better_networking/utils/auth/oauth2_utils.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
import 'oauth1_utils.dart';
|
||||||
|
|
||||||
Future<HttpRequestModel> handleAuth(
|
Future<HttpRequestModel> handleAuth(
|
||||||
HttpRequestModel httpRequestModel,
|
HttpRequestModel httpRequestModel,
|
||||||
AuthModel? authData,
|
AuthModel? authData,
|
||||||
@@ -157,8 +159,24 @@ Future<HttpRequestModel> handleAuth(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case APIAuthType.oauth1:
|
case APIAuthType.oauth1:
|
||||||
// TODO: Handle this case.
|
if (authData.oauth1 != null) {
|
||||||
throw UnimplementedError();
|
final oauth1Model = authData.oauth1!;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final client = generateOAuth1AuthHeader(
|
||||||
|
oauth1Model,
|
||||||
|
httpRequestModel,
|
||||||
|
);
|
||||||
|
|
||||||
|
updatedHeaders.add(
|
||||||
|
NameValueModel(name: 'Authorization', value: client),
|
||||||
|
);
|
||||||
|
updatedHeaderEnabledList.add(true);
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception('OAuth 1.0 authentication failed: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case APIAuthType.oauth2:
|
case APIAuthType.oauth2:
|
||||||
final oauth2 = authData.oauth2;
|
final oauth2 = authData.oauth2;
|
||||||
|
|
||||||
|
|||||||
121
packages/better_networking/lib/utils/auth/oauth1_utils.dart
Normal file
121
packages/better_networking/lib/utils/auth/oauth1_utils.dart
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:developer';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:math' as math;
|
||||||
|
import 'package:crypto/crypto.dart';
|
||||||
|
|
||||||
|
import '../../models/models.dart';
|
||||||
|
|
||||||
|
/// Generates a simple OAuth 1.0a Authorization header directly from model
|
||||||
|
String generateOAuth1AuthHeader(
|
||||||
|
AuthOAuth1Model oauth1Model,
|
||||||
|
HttpRequestModel request,
|
||||||
|
) {
|
||||||
|
// Generate OAuth parameters
|
||||||
|
final timestamp = (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString();
|
||||||
|
final nonce = _generateNonce();
|
||||||
|
|
||||||
|
// Build OAuth parameters map
|
||||||
|
final oauthParams = <String, String>{
|
||||||
|
'oauth_consumer_key': oauth1Model.consumerKey,
|
||||||
|
'oauth_signature_method': "HMAC-SHA1",
|
||||||
|
'oauth_timestamp': timestamp,
|
||||||
|
'oauth_nonce': nonce,
|
||||||
|
'oauth_version': oauth1Model.version,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add oauth_token if available
|
||||||
|
if (oauth1Model.accessToken != null && oauth1Model.accessToken!.isNotEmpty) {
|
||||||
|
oauthParams['oauth_token'] = oauth1Model.accessToken!;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create signature base string and signing key
|
||||||
|
final method = request.method.name.toUpperCase();
|
||||||
|
final uri = Uri.parse(request.url);
|
||||||
|
final baseString = _createSignatureBaseString(method, uri, oauthParams);
|
||||||
|
final signingKey =
|
||||||
|
'${Uri.encodeComponent(oauth1Model.consumerSecret)}&'
|
||||||
|
'${Uri.encodeComponent(oauth1Model.tokenSecret ?? '')}';
|
||||||
|
|
||||||
|
// Generate signature using HMAC-SHA1
|
||||||
|
final signature = _generateHmacSha1Signature(baseString, signingKey);
|
||||||
|
oauthParams['oauth_signature'] = signature;
|
||||||
|
|
||||||
|
// Build Authorization header
|
||||||
|
final authParts = oauthParams.entries
|
||||||
|
.map((e) => '${e.key}="${Uri.encodeComponent(e.value)}"')
|
||||||
|
.join(',');
|
||||||
|
|
||||||
|
return 'OAuth $authParts';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function to clear saved OAuth 1.0 credentials
|
||||||
|
Future<void> clearOAuth1Credentials(File credentialsFile) async {
|
||||||
|
if (await credentialsFile.exists()) {
|
||||||
|
try {
|
||||||
|
await credentialsFile.delete();
|
||||||
|
log('Cleared OAuth 1.0 credentials');
|
||||||
|
} catch (e) {
|
||||||
|
log('Error clearing OAuth 1.0 credentials: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates a random nonce for OAuth 1.0a
|
||||||
|
String _generateNonce() {
|
||||||
|
const chars =
|
||||||
|
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||||
|
final random = math.Random.secure();
|
||||||
|
return String.fromCharCodes(
|
||||||
|
Iterable.generate(
|
||||||
|
16,
|
||||||
|
(_) => chars.codeUnitAt(random.nextInt(chars.length)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates the signature base string for OAuth 1.0a
|
||||||
|
String _createSignatureBaseString(
|
||||||
|
String method,
|
||||||
|
Uri uri,
|
||||||
|
Map<String, String> parameters,
|
||||||
|
) {
|
||||||
|
// Combine OAuth parameters with query parameters
|
||||||
|
final allParameters = <String, String>{...parameters};
|
||||||
|
|
||||||
|
// Add query parameters from the URI
|
||||||
|
uri.queryParameters.forEach((key, value) {
|
||||||
|
allParameters[key] = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort parameters by key
|
||||||
|
final sortedKeys = allParameters.keys.toList()..sort();
|
||||||
|
|
||||||
|
// Create parameter string
|
||||||
|
final paramString = sortedKeys
|
||||||
|
.map(
|
||||||
|
(key) =>
|
||||||
|
'${Uri.encodeComponent(key)}=${Uri.encodeComponent(allParameters[key]!)}',
|
||||||
|
)
|
||||||
|
.join('&');
|
||||||
|
|
||||||
|
// Create base URI (without query parameters)
|
||||||
|
final baseUri = uri.replace(queryParameters: {}).toString();
|
||||||
|
|
||||||
|
// Create signature base string
|
||||||
|
return '${method.toUpperCase()}&'
|
||||||
|
'${Uri.encodeComponent(baseUri)}&'
|
||||||
|
'${Uri.encodeComponent(paramString)}';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generates HMAC-SHA1 signature for OAuth 1.0a
|
||||||
|
String _generateHmacSha1Signature(String baseString, String key) {
|
||||||
|
final keyBytes = utf8.encode(key);
|
||||||
|
final messageBytes = utf8.encode(baseString);
|
||||||
|
|
||||||
|
final hmac = Hmac(sha1, keyBytes);
|
||||||
|
final digest = hmac.convert(messageBytes);
|
||||||
|
|
||||||
|
return base64Encode(digest.bytes);
|
||||||
|
}
|
||||||
80
pubspec.lock
80
pubspec.lock
@@ -55,38 +55,6 @@ packages:
|
|||||||
relative: true
|
relative: true
|
||||||
source: path
|
source: path
|
||||||
version: "0.0.1"
|
version: "0.0.1"
|
||||||
app_links:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: app_links
|
|
||||||
sha256: "85ed8fc1d25a76475914fff28cc994653bd900bc2c26e4b57a49e097febb54ba"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "6.4.0"
|
|
||||||
app_links_linux:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: app_links_linux
|
|
||||||
sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.3"
|
|
||||||
app_links_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: app_links_platform_interface
|
|
||||||
sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.2"
|
|
||||||
app_links_web:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: app_links_web
|
|
||||||
sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.4"
|
|
||||||
archive:
|
archive:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -782,14 +750,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.2"
|
version: "2.3.2"
|
||||||
gtk:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: gtk
|
|
||||||
sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.1.0"
|
|
||||||
har:
|
har:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1198,6 +1158,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.0.2"
|
||||||
|
oauth1:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: oauth1
|
||||||
|
sha256: "1d424e3c24017a6c5714acb12e0dd76c2fdff96db6d6ef0aab58c925ffc28ae0"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
oauth2:
|
oauth2:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -2034,38 +2002,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.1"
|
version: "1.2.1"
|
||||||
webview_flutter:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: webview_flutter
|
|
||||||
sha256: c3e4fe614b1c814950ad07186007eff2f2e5dd2935eba7b9a9a1af8e5885f1ba
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "4.13.0"
|
|
||||||
webview_flutter_android:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: webview_flutter_android
|
|
||||||
sha256: "9573ad97890d199ac3ab32399aa33a5412163b37feb573eb5b0a76b35e9ffe41"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "4.8.2"
|
|
||||||
webview_flutter_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: webview_flutter_platform_interface
|
|
||||||
sha256: f0dc2dc3a2b1e3a6abdd6801b9355ebfeb3b8f6cde6b9dc7c9235909c4a1f147
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.13.1"
|
|
||||||
webview_flutter_wkwebview:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: webview_flutter_wkwebview
|
|
||||||
sha256: "71523b9048cf510cfa1fd4e0a3fa5e476a66e0884d5df51d59d5023dba237107"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "3.22.1"
|
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
Reference in New Issue
Block a user