UserModel showing error for status of the user - firebase

Can somebody help me in resolving the error. There is an error in UserModel.fromDocumentSnapshot. ITs telling userstatus has to be initialized. I have initialized it but yet the error remains. Can somebody tell me what could be the error in tis code. Looking forward to resolve this error. Please do help me
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:get/get.dart';
import 'package:hogoco_meet_app/model/base_model.dart';
import 'package:hogoco_meet_app/services/firebasedb.dart';
enum UserStatus { Active, Inactive, None }
extension on String {
UserStatus get getuserStatus {
switch (this) {
case 'Active':
return UserStatus.Active;
break;
case 'Inactive':
return UserStatus.Inactive;
break;
default:
return UserStatus.None;
break;
}
}
}
extension ExtendedUserStatus on UserStatus {
bool get active => this == UserStatus.Active;
bool get inactive => this == UserStatus.Inactive;
bool get none => this == UserStatus.None;
String get getuserStatus {
switch (this) {
case UserStatus.Active:
return 'Active';
break;
case UserStatus.Inactive:
return 'Inactive';
break;
default:
return 'None';
break;
}
}
}
class UserModel extends BaseModel {
String? id;
String? userProfilePhotoUrl;
String? userFullName;
String? userEmail;
UserStatus userStatus;
bool? userIsVerified;
Timestamp? userRegDate;
Timestamp? userLastLoginDate;
List<UserModel>? userFriends;
UserModel(
{this.id,
this.userProfilePhotoUrl,
this.userFullName,
this.userEmail,
this.userStatus = UserStatus.Inactive,
this.userIsVerified,
this.userRegDate,
this.userLastLoginDate,
this.userFriends});
#override
String toString() {
return '''UserModel: {userRegDate = ${this.userRegDate},id = ${this.id},userFullName = ${this.userFullName},userProfilePhotoURL = ${this.userProfilePhotoUrl},
userEmail = ${this.userEmail},userFriends = ${this.userFriends},userIsVerified = ${this.userIsVerified},userStatus = ${this.userStatus}}''';
}
UserModel.fromDocumentSnapshot({DocumentSnapshot? documentSnapshot}) {
final _userStatus = ((documentSnapshot!.data()! as Map<String, dynamic>)
.containsKey('userStatus'))
? ((documentSnapshot.data()! as Map<String, dynamic>)["userStatus"]
as String)
.getuserStatus
: UserStatus.None;
id = documentSnapshot.id;
userProfilePhotoUrl = (documentSnapshot.data()
as Map<String, dynamic>)['userProfilePhotoUrl'];
userFullName =
(documentSnapshot.data() as Map<String, dynamic>)["userFullName"];
userEmail = (documentSnapshot.data() as Map<String, dynamic>)["userEmail"];
userStatus = _userStatus;
userIsVerified =
(documentSnapshot.data() as Map<String, dynamic>)["userIsVerified"];
userRegDate =
(documentSnapshot.data() as Map<String, dynamic>)['userRegDate'];
userLastLoginDate =
(documentSnapshot.data() as Map<String, dynamic>)['userLastLoginDate'];
userFriends =
(documentSnapshot.data() as Map<String, dynamic>)["userFriends"];
}
}
class UserCrud {
final FirebaseService<UserModel> firebaseService =
Get.put(FirebaseService<UserModel>());
static const String Collection = FirebaseCollections.USER;
Stream<List<UserModel>> get getUsers {
return firebaseService.getListStream(
collection: Collection,
returnVal: (query) {
final retVal = <UserModel>[];
query.docs.forEach((element) {
retVal.add(UserModel.fromDocumentSnapshot(documentSnapshot: element));
});
return retVal;
},
);
}
}
Error
error: Non-nullable instance field 'userStatus' must be initialized. (not_initialized_non_nullable_instance_field at [hogoco_meet_app] lib\model\user_model.dart:71)

The userStatus field is the only field that is declared non-nullable, which means you have to initialize it before the constructor is executed.
UserModel.fromDocumentSnapshot({DocumentSnapshot? documentSnapshot}) is called a named constructor, therefore to be able to use it you need to initialize the userStatus first and you can do that by adding it to the initializer list:
UserModel.fromDocumentSnapshot({DocumentSnapshot? documentSnapshot}) : userStatus = UserStatus.Inactive {
final _userStatus = ((documentSnapshot!.data()! as Map<String, dynamic>)
.containsKey('userStatus'))
? ((documentSnapshot.data()! as Map<String, dynamic>)["userStatus"]
as String)
.getuserStatus
: UserStatus.None;
id = documentSnapshot.id;
userProfilePhotoUrl = (documentSnapshot.data()
as Map<String, dynamic>)['userProfilePhotoUrl'];
userFullName =
(documentSnapshot.data() as Map<String, dynamic>)["userFullName"];
userEmail = (documentSnapshot.data() as Map<String, dynamic>)["userEmail"];
userStatus = _userStatus;
userIsVerified =
(documentSnapshot.data() as Map<String, dynamic>)["userIsVerified"];
userRegDate =
(documentSnapshot.data() as Map<String, dynamic>)['userRegDate'];
userLastLoginDate =
(documentSnapshot.data() as Map<String, dynamic>)['userLastLoginDate'];
userFriends =
(documentSnapshot.data() as Map<String, dynamic>)["userFriends"];
}

Related

Converting data from firebase to an object does not work because of timestamp

I need to convert data from firebase to an object, but I get an error because of the Timestamp:
type 'Timestamp' is not a subtype of type 'Map<String, dynamic>'
In the model I added toDate() to the 'createdAt' but I still get the error.
How can I solve this in flutter?
import 'package:cloud_firestore/cloud_firestore.dart';
class AnimalWithLoc {
final String username;
final String userId;
final double longitude;
final double latitude;
final List<String> imageUrls;
final String description;
final DateTime createdAt;
final String address;
AnimalWithLoc(
this.username,
this.userId,
this.longitude,
this.latitude,
this.imageUrls,
this.description,
this.createdAt,
this.address,
);
AnimalWithLoc.fromMap(Map<String, dynamic> map)
: username = map['username'],
userId = map['userId'],
longitude = map['longitude'],
latitude = map['latitude'],
imageUrls = map['imageUrls'],
description = map['description'],
createdAt = (map["createdAt"] as Timestamp).toDate(),
address = map['address'];
}
in body.dart the foreach works correctly
...
final animalDocs = animalSnapshot.data!.docs;
final List<AnimalWithLoc> loadedAnimals = [];
for (var i = 0; i < animalDocs.length; i++) {
var currAnim = animalDocs[i].data();
currAnim.forEach((key, value) {
// print(value);
loadedAnimals.add(AnimalWithLoc.fromMap(value));
});
}
...
I think you are losing the toDate() method when you pass the data as a Map<String, dynamic>.
Try this in body.dart:
for (var i = 0; i < animalDocs.length; i++) {
var currAnim = animalDocs[i].data();
final createdAt = DateTime.parse(currAnim["createdAt"].toDate().toString());
}

The argumnet type 'Null Funcion(DataSnapshot)' cnt be assigned to the parameter type 'Future Or <dynamic> Function(DataBaseEvent)'

I have this function that is giving me an error.
the getCurrentOnLineUserInfo function is trying to get read data from the Firebase Database of the current user that is logged in.
The argument type 'Null Funcion(DataSnapshot)' can't be assigned to the parameter of type 'Future Or Function(DataBaseEvent)'
I am following a year-old tutorial, so the issue might be the code is old. I might need new syntax or something.
static void getCurrentOnLineUserInfo() async {
firebaseUser = await FirebaseAuth.instance.currentUser;
String userId = firebaseUser!.uid;
DatabaseReference reference =
FirebaseDatabase.instance.ref().child("user").child(userId);
print("getCurrentOnLineUser info executed!");
print('${firebaseUser!.email}${firebaseUser!.displayName}');
// errors below this
reference.once().then((DataSnapshot dataSnapshot) {
if (dataSnapShot!.value != null) {
userCurrentInfo = Users.fromSnapshot(dataSnapshot);
}
});
}
}
and here is my class that is assigning data. This class is giving no errors
class Users {
String? id;
String? email;
String? phone;
String? name;
Users({this.id, this.email, this.phone, this.name});
Users.fromSnapshot(DataSnapshot dataSnapshot) {
id = dataSnapshot.key!;
var data = dataSnapshot.value as Map?;
if (data != null) {
email = data?["email"];
name = data?["name"];
phone = data?["phone"];
}
}
}
The once method returns a DatabaseEvent, not a DataSnapshot. DatabaseEvent is a class that encapsulates a DataSnapshot AND a DatabaseEventType, to extract the snapshot, you must use DatabaseEvent.snapshot:
reference.once().then((event) {
final dataSnapshot = event.snapshot;
if (dataSnapShot!.value != null) {
userCurrentInfo = Users.fromSnapshot(dataSnapshot);
}
});
Here is another solution I think might do what you want:
// async methods should return a future
static Future<void> getCurrentOnLineUserInfo() async {
firebaseUser = await FirebaseAuth.instance.currentUser;
String userId = firebaseUser!.uid;
DatabaseReference reference =
FirebaseDatabase.instance.ref().child("user").child(userId);
final snapshot = await reference.get(); // you should use await on async methods
if (snapshot!.value != null) {
userCurrentInfo = Users.fromSnapshot(snapshot);
}
}
}
I was following the same old tutorial you mentioned, the #mobdev991 answer is correct and i think the reason why you don't receive data is the class where you are assigning data try this
class Users {
String? id;
String? email;
String? name;
String? phone;
Users({this.id, this.email, this.name, this.phone});
Users.fromSnapshot(DataSnapshot dataSnapshot) {
id = dataSnapshot.key;
email = (dataSnapshot.child("email").value.toString());
name = (dataSnapshot.child("name").value.toString());
phone = (dataSnapshot.child("phone").value.toString());
}
}

How to show product by category flutter Firestore

I'm trying to filter my list by category but no success so far. I've tried several ways to implement it and also asked some friends. Unfortunately non of their answers has worked yet.
This is the full code for the screen. I'd like to be able to filter documents by category, something like: "Where()"...
Any idea?
Thanks.
homeService file
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import 'package:tabib/core/view_model/services/home_sevices.dart';
import 'package:tabib/models/category_model.dart';
import 'package:tabib/models/doctor_model.dart';
class HomeViewModel extends GetxController{
ValueNotifier<bool> get loading => _loading;
final ValueNotifier<bool> _loading = ValueNotifier(false);
List<CategoryModel> get categoryModel => _categoryModel;
final List<CategoryModel> _categoryModel = [];
List<DoctorsModel> get doctorsyModel => _doctorsyModel;
final List<DoctorsModel> _doctorsyModel = [];
HomeViewModel() {
getCategory();
getDoctors();
}
getCategory() async{
_loading.value = true;
HomeServices().getCategory().then((value) {
for(int i = 0; i< value.length; i++) {
_categoryModel.add(CategoryModel.fromJson(value[i].data() as Map<dynamic, dynamic>));
_loading.value = false;
}
update();
});
}
getDoctors() async {
_loading.value = true;
HomeServices().getDoctors().then((value) {
for(int i = 0; i< value.length; i++) {
_doctorsyModel.add(DoctorsModel.fromJson(value[i].data() as Map<dynamic, dynamic>));
_loading.value = false;
print(_doctorsyModel);
}
update();
});
}
}
import 'package:cloud_firestore/cloud_firestore.dart';
class HomeServices{
final CollectionReference _categoryColletionRef =
FirebaseFirestore.instance.collection('categories');
final CollectionReference _doctorsColletionRef =
FirebaseFirestore.instance.collection('doctors');
Future<List<QueryDocumentSnapshot>> getCategory () async {
var value = await _categoryColletionRef.get();
return value.docs;
}
Future<List<QueryDocumentSnapshot>> getDoctors () async {
var value = await _doctorsColletionRef.get();
return value.docs;
}
}
class DoctorsModel {
late String name;
late String phone;
late String subCat;
DoctorsModel({required this.name,required this.phone, required this.subCat});
DoctorsModel.fromJson(Map<dynamic, dynamic> map) {
if(map == null) {
return;
}
name = map ['name'];
phone = map ['phone'];
subCat = map ['subCat'];
}
toJson() {
return {
'name': name,
'phone': phone,
'subCat': subCat,
};
}
}
class CategoryModel {
late String title;
late String image;
late int catID;
CategoryModel ({required this.catID,required this.title, required this.image});
CategoryModel.fromJson(Map<dynamic, dynamic> map) {
if (map == null) {
return;
}
catID = map['catID'];
title = map['title'];
image = map['image'];
}
toJson() {
return {
'catID': catID,
'title': title,
'image': image,
};
}
}
Posting Frank van Puffelen's comment as a Wiki answer for visibility.
You can filter your documents by category using querying methods described in the FlutterFire docs.
For example, the where method:
FirebaseFirestore.instance
.collection('categories')
.where()
.get()
.then(...);

Flutter - auto complete textfield with suggestions from sqlite database

Auto complete textfield with suggestions from sqlite database. Show one of the data from salute database as title and another as subtitle in the listtile of suggestions. I have used the sqlite plugin
Data model
class Note {
int _id;
String _title;
String _description;
var _chatEnabled;
var _liveEnabled;
var _recordEnabled;
var _raiseEnabled;
var _shareYtEnabled;
var _kickOutEnabled;
String _time;
String _host;
Note(this._title, this._description, this._time, this._chatEnabled, this._liveEnabled, this._recordEnabled, this._raiseEnabled, this._shareYtEnabled, this._kickOutEnabled, this._host);
Note.map(dynamic obj) {
this._id = obj['id'];
this._title = obj['title'];
this._description = obj['description'];
this._time = obj['time'];
this._chatEnabled = obj['chatEnabled'];
this._liveEnabled = obj['liveEnabled'];
this._recordEnabled = obj['recordEnabled'];
this._raiseEnabled = obj['raiseEnabled'];
this._shareYtEnabled = obj['shareYtEnabled'];
this._kickOutEnabled = obj['kickOutEnabled'];
this._host = obj['host'];
}
int get id => _id;
String get title => _title;
String get description => _description;
String get time => _time;
int get chatEnabled => _chatEnabled;
int get liveEnabled => _liveEnabled;
int get recordEnabled => _recordEnabled;
int get raiseEnabled => _raiseEnabled;
int get shareYtEnabled => _shareYtEnabled;
int get kickOutEnabled => _kickOutEnabled;
String get host => _host;
Map<String, dynamic> toMap() {
var map = new Map<String, dynamic>();
if (_id != null) {
map['id'] = _id;
}
map['title'] = _title;
map['description'] = _description;
map['time'] = _time;
map['chatEnabled'] = _chatEnabled;
map['liveEnabled'] = _liveEnabled;
map['recordEnabled'] = _recordEnabled;
map['raiseEnabled'] = _raiseEnabled;
map['shareYtEnabled'] = _shareYtEnabled;
map['kickOutEnabled'] = _kickOutEnabled;
map['host'] = _host;
return map;
}
Note.fromMap(Map<String, dynamic> map) {
this._id = map['id'];
this._title = map['title'];
this._description = map['description'];
this._time = map['time'];
this._chatEnabled = map['chatEnabled'];
this._liveEnabled = map['liveEnabled'];
this._recordEnabled = map['recordEnabled'];
this._raiseEnabled = map['raiseEnabled'];
this._shareYtEnabled = map['shareYtEnabled'];
this._kickOutEnabled = map['kickOutEnabled'];
this._host = map['host'];
}
}
DB manager
class DatabaseHelper {
static final DatabaseHelper _instance = new DatabaseHelper.internal();
factory DatabaseHelper() => _instance;
final String tableRecentJ = 'jrecentTable';
final String columnId = 'id';
final String columnTitle = 'title';
final String columnDescription = 'description';
final String columnTime = 'time';
final String chatEnabled = 'chatEnabled';
final String liveEnabled = 'liveEnabled';
final String recordEnabled = 'recordEnabled';
final String raiseEnabled = 'raiseEnabled';
final String shareYtEnabled = 'shareYtEnabled';
final String kickOutEnabled = 'kickOutEnabled';
final String host = 'host';
static Database _db;
DatabaseHelper.internal();
Future<Database> get db async {
if (_db != null) {
return _db;
}
_db = await initDb();
return _db;
}
initDb() async {
String databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'jrecent.db');
// await deleteDatabase(path); // just for testing
var db = await openDatabase(path, version: 1, onCreate: _onCreate);
return db;
}
void _onCreate(Database db, int newVersion) async {
await db.execute(
'CREATE TABLE $tableRecentJ($columnId INTEGER PRIMARY KEY, $columnTitle TEXT, $columnDescription TEXT, $columnTime TEXT, $chatEnabled INTEGER, $liveEnabled INTEGER, $recordEnabled INTEGER, $raiseEnabled INTEGER, $shareYtEnabled INTEGER, $kickOutEnabled INTEGER, $host TEXT)');
}
Future<int> saveNote(Note note) async {
var dbClient = await db;
var result = await dbClient.insert(tableRecentJ, note.toMap());
// var result = await dbClient.rawInsert(
// 'INSERT INTO $tableNote ($columnTitle, $columnDescription) VALUES (\'${note.title}\', \'${note.description}\')');
return result;
}
Future<List> getAllNotes() async {
var dbClient = await db;
var result = await dbClient.query(tableRecentJ, columns: [columnId, columnTitle, columnDescription, columnTime, chatEnabled, liveEnabled, recordEnabled, raiseEnabled, shareYtEnabled, kickOutEnabled, host]);
// var result = await dbClient.rawQuery('SELECT * FROM $tableNote');
return result.toList();
}
Future<int> getCount() async {
var dbClient = await db;
return Sqflite.firstIntValue(await dbClient.rawQuery('SELECT COUNT(*) FROM $tableRecentJ'));
}
Future<Note> getNote(int id) async {
var dbClient = await db;
List<Map> result = await dbClient.query(tableRecentJ,
columns: [columnId, columnTitle, columnDescription, columnTime, chatEnabled, liveEnabled, recordEnabled, raiseEnabled, shareYtEnabled, kickOutEnabled, host],
where: '$columnId = ?',
whereArgs: [id]);
// var result = await dbClient.rawQuery('SELECT * FROM $tableNote WHERE $columnId = $id');
if (result.length > 0) {
return new Note.fromMap(result.first);
}
return null;
}
Future<int> deleteNote(int id) async {
var dbClient = await db;
return await dbClient.delete(tableRecentJ, where: '$columnId = ?', whereArgs: [id]);
// return await dbClient.rawDelete('DELETE FROM $tableNote WHERE $columnId = $id');
}
Future<int> cleanNote() async {
var dbClient = await db;
return await dbClient.delete(tableRecentJ);
// return await dbClient.rawDelete('DELETE FROM $tableNote WHERE $columnId = $id');
}
Future<int> updateNote(Note note) async {
var dbClient = await db;
return await dbClient.update(tableRecentJ, note.toMap(), where: "$columnId = ?", whereArgs: [note.id]);
// return await dbClient.rawUpdate(
// 'UPDATE $tableNote SET $columnTitle = \'${note.title}\', $columnDescription = \'${note.description}\' WHERE $columnId = ${note.id}');
}
Future close() async {
var dbClient = await db;
return dbClient.close();
}
}
I want to show title and description in the suggestion of the textfield. How get the desired result?
Sorry, but your question is not clear.
I am guessing you want to autocomplete view in your textfile
Here is the package that provides the same.
https://pub.dev/packages/flutter_typeahead
Take look at it.

How to make Digest Authentication with http in Flutter?

I am trying to make an ApI request with Digest Authentication. I found an answer to the above question FLUTTER How to implement Digest Authentification but it is not very clear. The docs for digest are very minimal.
Following is my code
import 'package:http/io_client.dart' as io_client;
import 'package:http/http.dart' as http;
try {
HttpClient authenticatingClient = HttpClient();
authenticatingClient.authenticate = (uri, scheme, realm) {
authenticatingClient.addCredentials(
uri,
realm,
HttpClientDigestCredentials(
DIGEST_AUTH_USERNAME, DIGEST_AUTH_PASSWORD));
return Future.value(true);
};
http.Client client = io_client.IOClient(authenticatingClient);
final response = await client.post(LOGIN_URL, body: {
"username": userName,
"password": password,
"user_group": 2
}).timeout(const Duration(seconds: 20));
if (response.statusCode == 200) {
debugPrint(response.body);
CurvesLoginModel curvesLoginModel = standardSerializers.deserializeWith(
CurvesLoginModel.serializer, json.decode(response.body));
return curvesLoginModel;
} else {
return null;
}
} on TimeoutException catch (_) {
return null;
} on SocketException catch (_) {
return null;
}
}
But what is realm in addCredentials.
Also is this the way to implement Digest Authentication in http for Flutter?
As soon as I hit my endpoint I get the following error Unhandled Exception: type 'int' is not a subtype of type 'String' in type cast
Realm is an arbitrary string provided by the web server to help you decide which username to use, in case you have more than one. It's sort of analogous to domain. In one domain your username might be fbloggs, in another fredb. By telling you the realm/domain you know which to provide.
Your cast problem is caused by using the value 2 in the body. That must be a Map<String, String>, but you have provided an integer. Replace it with 2.toString().
If somebody wants to know how to make digest auth with http then it is as follows
import 'dart:async';
import 'dart:convert';
import 'dart:math' as math;
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart' as crypto;
import 'package:http/http.dart' as http;
class DigestAuthClient extends http.BaseClient {
DigestAuthClient(String username, String password, {inner})
: _auth = DigestAuth(username, password),
// ignore: prefer_if_null_operators
_inner = inner == null ? http.Client() : inner;
final http.Client _inner;
final DigestAuth _auth;
void _setAuthString(http.BaseRequest request) {
request.headers['Authorization'] =
_auth.getAuthString(request.method, request.url);
}
#override
Future<http.StreamedResponse> send(http.BaseRequest request) async {
final response = await _inner.send(request);
if (response.statusCode == 401) {
final newRequest = copyRequest(request);
final String authInfo = response.headers['www-authenticate'];
_auth.initFromAuthorizationHeader(authInfo);
_setAuthString(newRequest);
return _inner.send(newRequest);
}
// we should reach this point only with errors other than 401
return response;
}
}
Map<String, String> splitAuthenticateHeader(String header) {
if (header == null || !header.startsWith('Digest ')) {
return null;
}
String token = header.substring(7); // remove 'Digest '
var ret = <String, String>{};
final components = token.split(',').map((token) => token.trim());
for (final component in components) {
final kv = component.split('=');
ret[kv[0]] = kv.getRange(1, kv.length).join('=').replaceAll('"', '');
}
return ret;
}
String md5Hash(String data) {
var content = const Utf8Encoder().convert(data);
var md5 = crypto.md5;
var digest = md5.convert(content).toString();
return digest;
}
// from http_retry
/// Returns a copy of [original].
http.Request _copyNormalRequest(http.Request original) {
var request = http.Request(original.method, original.url)
..followRedirects = original.followRedirects
..persistentConnection = original.persistentConnection
..body = original.body;
request.headers.addAll(original.headers);
request.maxRedirects = original.maxRedirects;
return request;
}
http.BaseRequest copyRequest(http.BaseRequest original) {
if (original is http.Request) {
return _copyNormalRequest(original);
} else {
throw UnimplementedError(
'cannot handle yet requests of type ${original.runtimeType}');
}
}
// Digest auth
String _formatNonceCount(int nc) {
return nc.toRadixString(16).padLeft(8, '0');
}
String _computeHA1(String realm, String algorithm, String username,
String password, String nonce, String cnonce) {
String ha1;
if (algorithm == null || algorithm == 'MD5') {
final token1 = "$username:$realm:$password";
ha1 = md5Hash(token1);
} else if (algorithm == 'MD5-sess') {
final token1 = "$username:$realm:$password";
final md51 = md5Hash(token1);
final token2 = "$md51:$nonce:$cnonce";
ha1 = md5Hash(token2);
}
return ha1;
}
Map<String, String> computeResponse(
String method,
String path,
String body,
String algorithm,
String qop,
String opaque,
String realm,
String cnonce,
String nonce,
int nc,
String username,
String password) {
var ret = <String, String>{};
// ignore: non_constant_identifier_names
String HA1 = _computeHA1(realm, algorithm, username, password, nonce, cnonce);
// ignore: non_constant_identifier_names
String HA2;
if (qop == 'auth-int') {
final bodyHash = md5Hash(body);
final token2 = "$method:$path:$bodyHash";
HA2 = md5Hash(token2);
} else {
// qop in [null, auth]
final token2 = "$method:$path";
HA2 = md5Hash(token2);
}
final nonceCount = _formatNonceCount(nc);
ret['username'] = username;
ret['realm'] = realm;
ret['nonce'] = nonce;
ret['uri'] = path;
ret['qop'] = qop;
ret['nc'] = nonceCount;
ret['cnonce'] = cnonce;
if (opaque != null) {
ret['opaque'] = opaque;
}
ret['algorithm'] = algorithm;
if (qop == null) {
final token3 = "$HA1:$nonce:$HA2";
ret['response'] = md5Hash(token3);
} else if (qop == 'auth' || qop == 'auth-int') {
final token3 = "$HA1:$nonce:$nonceCount:$cnonce:$qop:$HA2";
ret['response'] = md5Hash(token3);
}
return ret;
}
class DigestAuth {
DigestAuth(this.username, this.password);
String username;
String password;
// must get from first response
String _algorithm;
String _qop;
String _realm;
String _nonce;
String _opaque;
int _nc = 0; // request counter
String _cnonce; // client-generated; should change for each request
String _computeNonce() {
math.Random rnd = math.Random();
List<int> values = List<int>.generate(16, (i) => rnd.nextInt(256));
return hex.encode(values);
}
String getAuthString(String method, Uri url) {
_cnonce = _computeNonce();
_nc += 1;
// if url has query parameters, append query to path
var path = url.hasQuery ? "${url.path}?${url.query}" : url.path;
// after the first request we have the nonce, so we can provide credentials
var authValues = computeResponse(method, path, '', _algorithm, _qop,
_opaque, _realm, _cnonce, _nonce, _nc, username, password);
final authValuesString = authValues.entries
.where((e) => e.value != null)
.map((e) => [e.key, '="', e.value, '"'].join(''))
.toList()
.join(', ');
final authString = 'Digest $authValuesString';
return authString;
}
void initFromAuthorizationHeader(String authInfo) {
Map<String, String> values = splitAuthenticateHeader(authInfo);
_algorithm = values['algorithm'];
_qop = values['qop'];
_realm = values['realm'];
_nonce = values['nonce'];
_opaque = values['opaque'];
}
bool isReady() {
return _nonce != null;
}
}
Then when calling your api
final response =
await DigestAuthClient(DIGEST_AUTH_USERNAME, DIGEST_AUTH_PASSWORD)
.post(LOGIN_URL, body: {
"USERNAME": userName,
"PASSWORD": password,
"USER_GROUP": "2"
}).timeout(const Duration(seconds: 20));
All credit goes to the following library https://pub.dev/packages/http_auth

Resources