I am needing to encrypt a hive box, in which the box 'user_api' is to be called in Api_Page_() to receive user input to store inside said box. However, the encryptedBox is not defined within the class. The Hive Docs display the encryption code is to be done inside of the main() function, which I have done, but I am unsure of how to take the box outside of main().
Any help or advice is greatly appreciated!
My Code:
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// HIVE ENCRYPTION----------------------------------------
const secureStorage = FlutterSecureStorage();
final encryptionKey = await secureStorage.read(key: 'key');
if (encryptionKey == null) {
final key = Hive.generateSecureKey();
await secureStorage.write(
key: 'key',
value: base64Encode(key),
);
}
final key = await secureStorage.read(key: 'key');
final encryptKey = base64Url.decode(key);
print('Encryption key: $encryptKey');
// HIVE ENCRYPTION----------------------------------------
// HIVE INIT---------------------------------------------
Directory directory = await getApplicationDocumentsDirectory();
Hive.init(directory.path);
await Hive.initFlutter();
final encryptedBox = Hive.openBox<String>('user_api', encryptionCipher: HiveAesCipher(encryptKey)); // Initially Opens Box on App Start
// HIVE INIT---------------------------------------------
runApp(myApp());
}
class myApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false, // Removes Debug Banner. [Delete before app release]
title: 'App Title Placeholder',
home: API_Page_() // Calls API_Page_ class from api_page.dart
);
}
}
class API_Page_ extends StatelessWidget {
const API_Page_({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: RaisedButton(onPressed: () { var eBox = encryptedBox<String>('user_api');
},
)
);
}
}
Related
I am using this code that I got directly from pub.dev regarding initializing the camera and creating a list of available cameras
the list is created in a Future main() function but it is not being automatically called when I navigate to the CameraApp page. Has anyone run into this issue? How do I initialize the camera and create the list of available cameras when it navigates to the page with this code? Please help, thank you.
/// CameraApp is the Main Application.
class CameraApp extends StatelessWidget {
/// Default Constructor
const CameraApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: CameraExampleHome(),
);
}
}
List<CameraDescription> _cameras = <CameraDescription>[];
Future<void> main() async {
// Fetch the available cameras before initializing the app.
try {
WidgetsFlutterBinding.ensureInitialized();
_cameras = await availableCameras();
} on CameraException catch (e) {
_logError(e.code, e.description);
}
runApp(const CameraApp());
}
And this is the code where I call the CameraApp function from inside a button:
ElevatedButton(
onPressed: ()
{Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CameraApp()));},
child: const Text('Camera'),
style: ElevatedButton.styleFrom(
minimumSize: const Size(160.0, 35.0)),
),
You can create a kind of singleton to manage camera operations.
class CameraManager {
// Declare your camera list here
List<CameraDescription> _cameras = <CameraDescription>[];
// Constructor
CameraManager._privateConstructor() {}
// initialise instance
static final CameraManager instance =
CameraManager._privateConstructor();
// Add a getter to access camera list
List<CameraDescription> get cameras => _cameras;
// Init method
init() async {
try {
_cameras = await availableCameras();
} on CameraException catch (e) {
_logError(e.code, e.description);
}
}
// other needed methods to manage camera
...
}
And then in you main function
Future<void> main() async {
// Fetch the available cameras before initializing the app.
try {
WidgetsFlutterBinding.ensureInitialized();
await CameraManager.instance.init();
}
runApp(const CameraApp());
}
Then on other part of your application, you can import the singleton and access methods and properties with CameraManager.instance.*, for example CameraManager.instance.cameras access _cameras through the getter.
There are few things to consider here.. The implementation you did was right but you named the cameras as a private variable which will be accessed in a single dart file by adding an _ like _cameras. Removing that will make it globally available in all classes just by importing main.dart
Here is the full code
main.dart
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:trial/CameraExampleHome.dart';
List<CameraDescription> cameras = <CameraDescription>[];
void main() async {
try {
WidgetsFlutterBinding.ensureInitialized();
cameras = await availableCameras();
print(cameras);
} on CameraException catch (e) {
print(e.toString());
}
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(home: CameraApp());
}
}
class CameraApp extends StatelessWidget {
/// Default Constructor
const CameraApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
home: CameraExampleHome(),
);
}
}
cameraExampleHome.dart
import 'package:flutter/material.dart';
import 'main.dart';
class CameraExampleHome extends StatefulWidget {
const CameraExampleHome({Key? key}) : super(key: key);
#override
State<CameraExampleHome> createState() => _CameraExampleHomeState();
}
class _CameraExampleHomeState extends State<CameraExampleHome> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text("Available Cameras $cameras"),
//output: Available Cameras [CameraDescription(0, CameraLensDirection.back, 90), CameraDescription(1, CameraLensDirection.front, 270), CameraDescription(2, CameraLensDirection.front, 270)]
),
);
}
}
You could create a library file for Global Variables.
Create a file called "globals.dart" in your lib folder.
Declare the following line at the top.
library your_project_name.globals;
Then set your variable in it
List<CameraDescription> cameras = <CameraDescription>[];
Usage in main
import 'globals.dart' as globals;
main() {
...
globals.cameras = await availableCameras();
...
}
Then simply use the variable anywhere in your project.
import 'globals.dart' as globals;
globals.cameras...
Declare list of CameraDescription global instance as below:
List<CameraDescription> cameras = <CameraDescription>[];
Now you can access the camera instance by importing main.dart , _ always make the instance variable private which will not be accessible outside the file
I am creating a Login , Logout Page in flutter when i use Stream and Provider . I get Some Errors.
Help me out of this
in the main.dart when i use the StreamProvider it says the intial data cannot be null, according to my Tutorial there is no intialdata and in auth.dart when i use the authStatchanges().map it gives me 'The argument type 'Userid Function(User)' can't be assigned to the parameter type 'Userid Function(User?)'
Error Places - auth change user stream & and StreamProvider in main.dart
Thanks
Auth.dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:wasthu/Services/user.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
//create userobject based on firebase user
Userid? _userFromFirebaseUser(User user) {
return user != null ? Userid(uid: user.uid) : null;
}
// auth change user stream
Stream<Userid> get user {
return _auth
.authStateChanges()
.map((User user) => _userFromFirebaseUser(user));
}
//sign in anon
Future signInAnon() async {
try {
UserCredential result = await _auth.signInAnonymously();
User? user = result.user;
return _userFromFirebaseUser(user!);
} catch (e) {
print(e.toString());
return null;
}
}
//signout
Future signOut() async {
try {
return await _auth.signOut();
} catch (e) {
print(e.toString());
return null;
}
}
}
main.dart
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:wasthu/Screens/Home/wrapper.dart';
import 'package:wasthu/Services/auth.dart';
import 'package:wasthu/Services/user.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MaterialApp(
home: MyApp(),
debugShowCheckedModeBanner: false,
));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamProvider<Userid>.value(
value: AuthService().user,
initialData: null,
child: MaterialApp(
home: Wrapper(),
),
);
}
}
user.dart
class Userid {
final String uid;
Userid({required this.uid});
}
I'm tring to get data of signed in user from microsoft azure using microsoft graph api,
i'm getting access token and also login successfully,
but i'm getting error as : "Insufficient privileges to complete the operation."
My Code
import 'dart:convert';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:aad_oauth/aad_oauth.dart';
import 'package:aad_oauth/model/config.dart';
import 'package:exim_bank_leave_app/Utils/AppTheme.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'Screens/Listing.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: MyTheme.darkTheme(context),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
static var user;
static final Config config = Config(
tenant: 'f6------------------38',
clientId: 'cba-----------------f5',
scope: 'openid profile offline_access',
redirectUri: 'https://login.microsoftonline.com/common/oauth2/nativeclient',
);
static final AadOAuth oauth = AadOAuth(config);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
SharedPreferences prefs;
static final String accessToken = accessToken;
var token;
#override
void initState() {
super.initState();
loadData();
}
#override
Widget build(BuildContext context) {
// adjust window size for browser login
var screenSize = MediaQuery.of(context).size;
var rectSize =
Rect.fromLTWH(0.0, 25.0, screenSize.width, screenSize.height - 25);
MyHomePage.oauth.setWebViewScreenSize(rectSize);
return Scaffold(
body: Container(),
);
}
loadData() async {
var auth = MyHomePage.oauth;
await auth.login();
var accessToken = await auth.getAccessToken();
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => Listing()));
prefs = await SharedPreferences.getInstance();
while (prefs == null || accessToken == null) continue;
final String idToken = await auth.getIdToken();
setState(() {
prefs.setString('token', idToken);
});
print('Token $accessToken');
final graphResponse = await http.get('https://graph.microsoft.com/v1.0/me',
headers: {HttpHeaders.authorizationHeader: "Bearer $accessToken"});
print(graphResponse.body.toString());
print(graphResponse.statusCode);
}
static void logout() async {
await MyHomePage.oauth.logout();
}
}
Error : I/flutter (29743): {"error":{"code":"Authorization_RequestDenied","message":"Insufficient privileges to complete the operation.","innerError":{"date":"2021-10-04T10:28:54","request-id":"3b12c615-47f1-4d07-ab4e-b6f4907a5b11","client-request-id":"3b12c615-47f1-4d07-ab4e-b6f4907a5b11"}}}
Based on your code 'https://graph.microsoft.com/v1.0/me' you are using the /me
When Calling the /me endpoint requires a signed-in user and therefore a delegated permission. Application permissions are not supported when using the /me endpoint .So Add the Delegated permission to call ApI
Delegated permissions are
User.Read,
User.ReadWrite,
User.ReadBasic.All,
User.Read.All,
User.ReadWrite.All,
Directory.Read.All,
Directory.ReadWrite.All,
Directory.AccessAsUser.All
To add the permission
1) Under an application's API permissions page, choose Add a permission.
2) select Microsoft Graph.
3) Choose the Delegated permission. And Search all the permission and Click on the Add Permission.
For more details refer this document
I'm create a project on Flutter. And I'm using a provider to change screens in my app.
Here is my main.dart file:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:school_app/services/auth_service.dart';
import 'package:school_app/wrapper.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => AuthService().auth,
child: MaterialApp(
home: Wrapper(),
),
);
}
}
Also this is my wrapper.dart file where the screens choose:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:school_app/screens/authenticate/auth.dart';
import 'package:school_app/models/user.dart';
import 'package:school_app/screens/school/home.dart';
import 'package:school_app/services/auth_service.dart';
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final user = Provider.of<AuthProvider>(context);
print(user.auth);
if(!user.auth) return Auth();
return Home();
}
}
And it is my AuthProvider class:
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AuthService {
/* AuthUser _user(User user) {
return user != null ? AuthUser(uid: user.uid) : null;
}*/
AuthProvider auth = new AuthProvider();
//sign in
Future signIn(String username, String password) async {
try {
SharedPreferences prefs = await SharedPreferences.getInstance();
var dio = Dio();
Response user = await dio.post('url', data: {
'username': username,
'password': password
});
if(user.data['success'] == false) return user.data['msg'];
await prefs.setString('token', user.data['token']);
auth.setAuth(true);
print("SUCCESS");
} catch(e) {
print('Error ' + e.toString());
}
}
}
class AuthProvider with ChangeNotifier {
bool _auth;
AuthProvider() {
_auth = false;
}
bool get auth => _auth;
void setAuth(bool auth) {
_auth = auth;
notifyListeners();
}
}
And when I call a function in AuthProvider class setAuth, nothing changed. Can you help me and find my mistake?
EDIT
I'm making all changes that you writes but it is not working. Here is my main.dart:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:school_app/services/auth_service.dart';
import 'package:school_app/wrapper.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => AuthProvider(),
child: MaterialApp(
home: Wrapper(),
),
);
}
}
Also wrapper.dart:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:school_app/screens/authenticate/auth.dart';
import 'package:school_app/screens/school/home.dart';
import 'package:school_app/services/auth_service.dart';
class Wrapper extends StatefulWidget {
#override
_WrapperState createState() => _WrapperState();
}
class _WrapperState extends State<Wrapper> {
#override
void initState() {
// TODO: implement initState
super.initState();
AuthService().auth;
}
#override
Widget build(BuildContext context) {
return Consumer<AuthProvider>(builder: (context, authProvider, child) {
print(authProvider.auth);
if (!authProvider.auth) {
return Auth();
} else {
return Home();
}
});
}
}
And AuthService and AuthProvider classes:
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AuthService {
/* AuthUser _user(User user) {
return user != null ? AuthUser(uid: user.uid) : null;
}*/
AuthProvider auth = new AuthProvider();
//sign in
Future signIn(String username, String password) async {
try {
SharedPreferences prefs = await SharedPreferences.getInstance();
var dio = Dio();
Response user = await dio.post('url', data: {
'username': username,
'password': password
});
if(user.data['success'] == false) return user.data['msg'];
await prefs.setString('token', user.data['token']);
auth.setAuth(true);
print("SUCCESS");
} catch(e) {
print('Error ' + e.toString());
}
}
}
class AuthProvider with ChangeNotifier {
bool _auth;
AuthProvider() {
_auth = false;
}
bool get auth => _auth;
void setAuth(bool auth) {
_auth = auth;
notifyListeners();
}
}
Notice, that here two classes and in AuthService I'm calling function .setAuth(true).
In your current implementation of Wrapper, you are rendering the widget once and not listening to whether the values changed. You could use Consumer as suggested above. You could also choose to watch the value for changes - like this:
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
final user = context.watch<AuthProvider>();
print(user.auth);
if(!user.auth) return Auth();
return Home();
}
}
When you use a watch or Consumer pattern, the widget will be rendered when the values of the underlying store (which is AuthProvider here) gets changed.
The only missing part here is that you never Consume the AuthProvider to listen to the notifyListeners() trigger.
The correct implementation looks like the following (I didn't try it, you may have to correct some typo errors, but you'll get the idea !)
class Wrapper extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Consumer<AuthProvider>(
builder: (context, authProvider, child) {
if (!authProvider.auth) {
return Auth();
} else {
return Home();
}
}
);
}
}
EDIT
I didn't notice you weren't injecting the right Class in your ChangeNotifierProvider. You'll also have to update your widget MyApp
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => AuthProvider(),
child: MaterialApp(
home: Wrapper(),
),
);
}
And in this case you probably should transform your Wrapper widget to a Stateful widget, and in the initState method you should call AuthService().auth.
I strongly recommend you to read the official documentation of Provider, looks like things aren't crystal clear yet in your mind
EDIT 2
You're still missing the point of the Provider library.
The goal of this lib is to provide an instance of a class to your widget tree so you don't have to re-create an instance in each widget.
Here, in AuthService class you're re-creating a AuthProvider with AuthProvider auth = new AuthProvider(); instead of referring to the existing instance created in the parent Widget.
To refer to a previously created instance, you should use Provider.of<AuthProvider>(context); in the AuthService class, or, even better, pass the instance of AuthProvider as a parameter in the signIn method.
I am trying to see if an id key is available in my app's shared_pereferences and if there is, redirect my user to the homepage. I am checking the Id in the initState() function of my main.dart and I know that the id exists because I can get it in other pages. but in my main.dart it returns null. any ideas?
here is my main.dart code:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import './ui/pages/auth/auth_one.dart';
import './ui/pages/main_page.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() {
SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitDown, DeviceOrientation.portraitUp])
.then((_) => runApp(MyApp()));
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String userId;
#override
void initState() {
_getUserId().then((id) => userId = id);
super.initState();
}
#override
Widget build(BuildContext context) {
print(userId);
return MaterialApp(
theme: ThemeData(primarySwatch: Colors.deepPurple),
debugShowCheckedModeBanner: false,
home: userId == null ? AuthOne() : MainPage(),
);
}
_getUserId() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var id = prefs.getString('id');
return id;
}
}
Your _getUserId method is async, so you will have to refresh the widget after you get the result.
Use this:
#override
void initState() {
_getUserId().then((id) {
//calling setState will refresh your build method.
setState(() {
userId = id;
});
});
super.initState();
}
This is happening because you are trying to use the value before its calculated.
you could use timer function for delay