How to get Public IP in Flutter? - flutter

In my case, i need public IP Address. But, after research almost all documentary related to Local IP like: Get_IP, I want something like 202.xxx not 192.168.xxx. Can someone give some advice?

As far as I'm aware, there's no way to get the public IP of a device from within that device. This is because the vast majority of the time, the device doesn't know it's own public IP. The public IP is assigned to the device from the ISP, and your device is usually separated from the ISP through any number of modems, routers, switches, etc.
You need to query some external resource or API (such as ipify.org) that will then tell you what your public IP is. You can do this with a simple HTTP request.
import 'package:http/http.dart';
Future<String> getPublicIP() async {
try {
const url = 'https://api.ipify.org';
var response = await http.get(url);
if (response.statusCode == 200) {
// The response body is the IP in plain text, so just
// return it as-is.
return response.body;
} else {
// The request failed with a non-200 code
// The ipify.org API has a lot of guaranteed uptime
// promises, so this shouldn't ever actually happen.
print(response.statusCode);
print(response.body);
return null;
}
} catch (e) {
// Request failed due to an error, most likely because
// the phone isn't connected to the internet.
print(e);
return null;
}
}
EDIT: There is now a Dart package for getting public IP information from the IPify service. You can use this package in place of the above manual solution:
import 'package:dart_ipify/dart_ipify.dart';
void main() async {
final ipv4 = await Ipify.ipv4();
print(ipv4); // 98.207.254.136
final ipv6 = await Ipify.ipv64();
print(ipv6); // 98.207.254.136 or 2a00:1450:400f:80d::200e
final ipv4json = await Ipify.ipv64(format: Format.JSON);
print(ipv4json); //{"ip":"98.207.254.136"} or {"ip":"2a00:1450:400f:80d::200e"}
// The response type can be text, json or jsonp
}

I recently came across this package dart_ipify that can do this work.
https://pub.dev/packages/dart_ipify
Here is an example:
import 'package:dart_ipify/dart_ipify.dart';
void main() async {
final ipv6 = await Ipify.ipv64();
print(ipv6); // 98.207.254.136 or 2a00:1450:400f:80d::200e
}

I came across this topic recently.
After investigating the issue, I found a solution using an external API.
I am using ipstack, it has a generous free tier.
Request a free access key
Make the following POST call
http://api.ipstack.com/check?access_key=YOUR_ACCESS_KEY
You can extract the ip parameter from the response

Related

mongo_dart error: A value of type 'Rational' can't be assigned to a variable of type 'Decimal'

The code below tries to create a Dart server and open a Mongo database. When database section below is commented, then the server starts as expected. Uncommenting the database section dumps the below error on console.
../../.pub-cache/hosted/pub.dartlang.org/bson-
2.0.1/lib/src/types/decimal_128.dart:36:58: Error: A value of type 'Rational' can't
be assigned to a variable of type 'Decimal'.
Environment: MacOS_x64 12.6, Dart SDK version: 2.19.0-264.0.dev (dev)
import 'dart:io';
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart';
import 'package:shelf_router/shelf_router.dart';
import 'package:mongo_dart/mongo_dart.dart';
// Configure routes.
final _router = Router()
..get('/', _rootHandler)
..get('/echo/<message>', _echoHandler);
Response _rootHandler(Request req) {
return Response.ok('Hello, World!\n');
}
Response _echoHandler(Request request) {
final message = request.params['message'];
return Response.ok('$message\n');
}
void main(List<String> args) async {
// Use any available host or container IP (usually `0.0.0.0`).
final ip = InternetAddress.anyIPv4;
// Configure a pipeline that logs requests.
final handler = Pipeline().addMiddleware(logRequests()).addHandler(_router);
// For running in containers, we respect the PORT environment variable.
final port = int.parse(Platform.environment['PORT'] ?? '8080');
final server = await serve(handler, ip, port);
print('Server listening on port ${server.port}');
/// Database Section ///
final db = Db('mongodb://localhost:27017/testdb');
try {
print('Opening database\n');
await db.open();
print('database connected');
print('Database connected');
} catch (e) {
print(e);
exit(0);
}
}
It would seem that the bson package is to blame for the error. I would post an issue ticket on their repository detailing this issue, and also post an issue on the mongo_dart package bringing it to their attention. Perhaps they are using an outdated version of the decimal or rational package. (Or maybe this has already been fixed in the bson package and it's the mongo_dart package that needs to update its dependencies.)
Per the documentation, Decimal.pow returns a Rational, and Decimal and Rational are not directly compatible types. They would need to use the extension method Rational.toDecimal to convert the value back to a Decimal.
// For example
final Decimal maxUint64 = Decimal(2).pow(64).toDecimal();

Flutter - I can't make a request to the EC2 integration environment endpoint

I can't make a request to an AWS instance endpoint through Flutter. The line below is not even executed, as the code stops on the request.
Future getCode() async {
Response response = await client.get(
Uri.parse('http://ec2-54-202-27-94.sa-east-1.compute.amazonaws.com/test/api/v1/example'),
);
print(response.statusCode);
}
I am able to perform this same request through Postman.
However, when I make a request via Flutter to the same endpoint, changing the first part of the domain (making the request for the Production environment and not for Homologation), it works:
Integration URL (does not work in Flutter)
http://ec2-54-202-27-94.sa-east-1.compute.amazonaws.com/test/api/v1/example
Production URL (works in Flutter)
http://www.test.com/test/api/v1/example
I also emphasize that the integration environment is a copy of the production environment, which should allow access to both.
I believe that it is not necessary to make any changes to the server that receives these requests, as I can successfully make the request through Postman.
How can I make this request through Flutter?
Sample request URL for production environment
Sample request URL for homologation environment
It worked for the request to work by calling the endpont of the integration environment
For this it was necessary to use the badCertificateCallback and specify the certificate that I would like to allow access. I created a class specifying this:
class MyHttpOverrides extends HttpOverrides {
#override
HttpClient createHttpClient(SecurityContext context) {
return super.createHttpClient(context)
..badCertificateCallback = (X509Certificate cert, String host, int port) {
if (host.isNotEmpty &&
host == 'ec2-54-202-27-94.sa-east-1.compute.amazonaws.com') {
return true;
} else {
return false;
}
};
}
}
And in the project file that has the main function, add the following lines
WidgetsFlutterBinding.ensureInitialized();
HttpOverrides.global = MyHttpOverrides();
This way:
void main() {
WidgetsFlutterBinding.ensureInitialized();
HttpOverrides.global = MyHttpOverrides();
runApp(
MyApp(),
);
}
It is not appropriate to allow the use of insecure certificates in a production environment. Use only in Debug mode

Flutter authentication with email and password without using Firebase

Is it possible to achive authentication with email and password in flutter without using firebase? I have searched around Stackoverflow and internet in general and found nothing about this.
I am creating a simple authentication class this is what I have done at the moment:
class User {
bool isAuthenticated = false;
late String userid;
late String username;
late String email;
late DateTime expireDate; // this variable is used to make the user re-authenticate when today is expireDate
User(bool isAuthenticated, String userid, String username, String email) {
this.isAuthenticated = isAuthenticated;
this.userid = userid;
this.username = username;
this.email = email;
this.expireDate = new DateTime.now().add(new Duration(days: 30));
}
}
class Authentication {
Future<User> signin(String email, String password) {}
void signup(String username, String email, String password) {}
}
EDIT #1: I know how to setup a cookie/token based authentication server I have my own repos on that topic: cookie authentication, token authentication but I don't know how to handle the tokens/cookies in flutter.
This answer is based of #edit1. Since you mentioned that you already know how to set up tokens on the server side you're half way done. Here's a few assumptions I'm making, you already know js/php and worked with JSON output, The database already has a column and table that keeps track of sessions and user_id.
Since you know how Cookies are built this should be relatively easy cause i built it around similar architecture. We has to use the local memory that app's provide access to. There are two packages in flutter that allow u to do this, you can use either:
shared_preferences package link
flutter_secure_storage package link
The main difference is if you want to store 'tokens' or data you want secure you would obviously use flutter_secure_storage. I'm going to use this for code example. And yes the data is saved even after the app is closed.
Setting up Tokens(flutter):
Setting up User Class
When using firebase we generally take for granted the user class that comes with flutter_auth but that is basically what we have to build. A user class with all the data u want to store and then a function called authenticate.
class AppUser{
final _storage = new FlutterSecureStorage();
//below class is mentioned in the next part
AuthApi api = new AuthApi();
//constructor
AppUser(){
//ur data;
};
Future<bool> authenticate(email, password) async {
//this is the api mentioned in next part
http.Response res = await api.login(email, password);
Map<String, dynamic> jsonRes = jsonDecode(res.body);
if (jsonRes["error"]) {
return false;
}
_setToken(jsonRes["token"]);
_setUID(jsonRes["user-id"].toString());
_setAuthState(true);
return true;
}
Future<void> _setToken(String val) async {
//how to write to safe_storage
await _storage.write(key: 'token', value: val);
}
Future<void> _setUID(String val) async {
await _storage.write(key: 'user_id', value: val);
}
//you can stream this or use it in a wrapper to help navigate
Future<bool> isAuthenticated() async {
bool authState = await _getAuthState();
return authState;
}
Future<void> _getAuthState() async {
//how to read from safe_storage u can use the same to read token later just replace 'state' with 'token'
String myState = (await _storage.read(key: 'state')).toString();
//returns boolean true or false
return myState.toLowerCase() == 'true';
}
Future<void> _setAuthState(bool liveAuthState) async {
await _storage.write(key: 'state', value: liveAuthState.toString());
}
}
and assuming ur going to authenticate on a button press so it would look like
onPressed(){
AuthUser user = new AuthUser();
if(user.authenticate(email, password)){
//if logged in. Prolly call Navigator.
}else{
//handle error
}
}
Setting up api calls
Oka so this is calling a Node express API, and the json output looks like
//if successful
{"status":200, "error": false, "token": "sha256token", "user-id": "uid"}
we need to create a class that will give us an output for making this call hence the AuthApi class
class AuthApi {
//this is the login api and it returns the above JSON
Future<http.Response> login(String email, String password){
return http.post(
Uri.parse(ip + '/api/auth/login'),
headers: <String, String>{
'Content-Type': 'application/json',
},
body: jsonEncode(<String, String>{
"email": email,
"password": password,
}),
);
}
}
Thank you for clarifying what u needed, it helped answer better.
You can use Nodejs & express to create your own API and MongoDB or any other DB to act as a persistent DB. I am attaching my github repo link which has minimum code required to setup a email/password auth in mongodb
Github
EDIT :
I have little to no idea about sessions but for tokens there are packages in pub.dev which lets you decode the tokens. jwt-decoder.
You can check the expiry time of the token using this package and for storing them you can use secure_storage
I had a look at your token authentication repo. I would suggest you to verify the token when you get them and not just blindly trust them.
Yes it is Totally possible to create Authentication without Firebase, but it becomes a-lot more difficult and there are multiple solutions.
What firebase provides:
Server space with no down time
Complete set of Api's including authentication with various methods
Strong security(built by google)
Ease of use and setup with great documentation
The reason I bring these up is cause the alternative ur looking for is very difficult for a programer who's relatively new and can feel like you are building multiple applications at a time. It's definitely a learning curve. Also I'm assuming u don't just want local authentication cause thats kinda pointless.
Creating ur own backend involves:
Setting up a server(usually ubuntu)(and either on a raspi or a host like amazon, digital ocean, etc)
Setting up a database with tables(mysql, sql, mongoDB)
Creating communication API's (php, Node.js)
So here's what i'd recommend for getting into backend dev,
use LAMP architecture : Linux, Apache, MySQL, PHP
Setting up Lamp isn't too hard heres a link i followed:
https://www.digitalocean.com/community/tutorials/how-to-install-linux-apache-mysql-php-lamp-stack-on-ubuntu-16-04
After u set up ur back end, then u have to create api calls from flutter.
The call (if u created an auth.php where people can login) would look something like:
http://ip:8080/auth.php?email="example#gmail.com"&pass="123456"
I understand why you feel like you didn't find solutions, i was there too but there are tons,LAMP is one of the more easier ones. If u are still interested i'd recommend checking out System Design courses.

How to push data from server to flutter app (send data from server to client without request)

I have a flutter app and it includes something like a chat.
I want to send the message from the server (which is ASP MVC API in my case) to my app so I check my API every 300(ms),
while it doesn't make sense; so what the best way I can do to send data from the server to my app?
meanwhile, i can't use firebase (in Syria)
I'm sure that it's a duplicated question but I didn't find my answer anywhere
It's ok to use SignalR where it allows you to push data from the server to the client, by calling a function on the client from the server and pass its parameters
here is some example:
server code:
public async void sendMessageToServer(string message, string sender){
await Clients.All.SendAsync("getMessageFromServer",message,sender);
}
client code(flutter):
in initState you must initialize your server connection
HubConnection hubConnection = HubConnectionBuilder().withUrl('serverurl').build();
await hubConnection.start();
hubConnection.on("getMessageFromServer", _newMessage);
then you send and receive data:
_newMessage(List<Object> args) async {
String message = args[0];
String sender = args[1];
}
void sendMessage(){
String message = 'Hello';
await hubConnection.invoke("sendMessageToServer", args: <Object>['MyName',message]);
}

Gathering performance metrics for calls to Cloud Functions from Flutter

I am attempting to use Firebase Performance monitoring with Firebase Cloud Functions. When I run the following code I get the error URL host is null or invalid. Clearly that is because I am passing in a function name rather than a URL with a host.
import 'package:flutter/widgets.dart';
import 'package:cloud_functions/cloud_functions.dart';
import 'package:firebase_performance/firebase_performance.dart';
/// Handles tracking metrics while calling cloud functions.
class MetricCloudFunction {
Future<HttpsCallableResult> call(String functionName, [dynamic parameters]) async {
final HttpMetric metric = FirebasePerformance.instance
.newHttpMetric(functionName, HttpMethod.Get);
final HttpsCallable callable = CloudFunctions.instance.getHttpsCallable(
functionName: functionName,
);
await metric.start();
HttpsCallableResult response;
try {
response = await callable.call(parameters);
} catch(e) {
debugPrint('failed: ${e.toString()}');
} finally {
await metric.stop();
}
return response;
}
}
Is there some way to get the URL of the callable function so that I can create the metric for it? If not, is there another way that I can create an HTTP metric for it?
There is currently no way to programmatically get the URL for an HTTP callable type function. You can compose it by what you know about the function (the three variables are deployment region, project ID, name), or you can simply copy it from the Firebase console Functions dashboard and hard code it into your app.