RTCPeerConnection and createDataChannel not working for Edge - reactjs

I have been working on an application where when a person logs into an account, the IP address of the device is stored in the backend and local storage. Then when a person logs into the same account from another browser or so, it will show a popup with the last login IP address. It seems to work on chrome and Mozilla but not working in edge browser. It always returns null because it's not entering the code after pc.createDataChannel.
The code snippet is as below.
const getIpAddress = state => {
window.RTCPeerConnection = window.RTCPeerConnection ||
window.mozRTCPeerConnection || window.webkitRTCPeerConnection || false;
let ip = false;
if (window.RTCPeerConnection) {
ip = [];
var pc = new RTCPeerConnection({ iceServers: [] }), noop = function
() {
};
pc.createDataChannel('');
pc.createOffer(pc.setLocalDescription.bind(pc), noop);
pc.onicecandidate = function (event) {
if (event && event.candidate && event.candidate.candidate) {
var s = event.candidate.candidate.split('\n');
ip.push(s[0].split(' ')[4]);
localStorage.setItem('ipV4Address', ip[0]);
}
};
}
return state;
};
I also tried using adapter js but not sure how to exactly use it.

WebRTC Peer-to-peer connections not yet supported fully on Edge v18 browser yet. You can check your browser compatible at Can I use RTCPeerConnection ?

It seems that there is no way to actually get the private ip in edge browser, so had to use a third party api to get public ip and use that.

Related

My dapp doesn't detect when an user change their Metamask Account

I am in the process of building a dapp for a project. I have one last thing to adjust: detect when a user changes metamask account to reset the state but it doesn't work.
//Doesn't work
window.ethereum.on('accountsChanged', function (accounts) {
console.log('accountsChanges', accounts);
setDefaultAccount(null);
});
// This works perfectly
window.ethereum.on('chainChanged', (chainId) => {
if(chainId !== "0x13881") {
setErrorMessage("Please connect on testnet Polygon Mumbai");
} else {
setErrorMessage(null);
window.location.reload();
}
});
I was also struggling with the same issue. Being unable to find the answer in the docs anywhere.
Until I'd realized that it's not meant to detect you switching from a connected account to a disconnected one.
In other words: it only detects it when you switch between accounts that are already connected to your Dapp. In that case - it functions perfectly. And detects an account change.
Go on ahead an test it on some popular Dapp out there. Connect just one of your accounts to it - then change it to another account on the same wallet, that is not yet connected - and it will also not be able to detect you changing it.
But if you connect two accounts right away - it will detect you switching between them and reflect your changes on its interface.
I tested this with PCS.
this is the correct way of implementation:
useEffect(() => {
ethereum?.on("accountsChanged", handleAccountChange);
return () => {
ethereum?.removeListener("accountsChanged", handleAccountChange);
};
});
Now write a listener for account change
const handleAccountChange = (...args) => {
// you can console to see the args
const accounts = args[0] ;
// if no accounts that means we are not connected
if (accounts.length === 0) {
console.log("Please connect to metamask");
// our old data is not current connected account
// currentAccount account that you already fetched and assume you stored it in useState
} else if (accounts[0] !== currentAccount) {
// if account changed you should update the currentAccount so you return the updated the data
// assuming you have [currentAccount,setCurrentAccount]=useState
// however you are tracking the state currentAccount, you have to update it. in case of redux you have to dispatch update action etc
setCurrentAccount(accounts[0)
}
};

Correct Flow for Google OAuth2 with PKCE through Client App to SAAS API Server

So we are working on a client application in Windows WPF. We want to include Google as a login option and intend to go straight to the current most secure method. At the moment we have spawned a web browser with the following methods to obtain a Authorization Code
private async void HandleGoogleLogin() {
State.Token = null;
var scopes = new string[] { "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "openid" };
var request = GoogleOAuthRequest.BuildLoopbackRequest(scopes);
var listener = new HttpListener();
listener.Prefixes.Add(request.RedirectUri);
listener.Start();
// note: add a reference to System.Windows.Presentation and a 'using System.Windows.Threading' for this to compile
await Dispatcher.Invoke(async () => {
googleLoginBrowser.Address = request.AuthorizationRequestUri;
});
// here, we'll wait for redirection from our hosted webbrowser
var context = await listener.GetContextAsync();
// browser has navigated to our small http servern answer anything here
string html = string.Format("<html><body></body></html>");
var buffer = Encoding.UTF8.GetBytes(html);
context.Response.ContentLength64 = buffer.Length;
var stream = context.Response.OutputStream;
var responseTask = stream.WriteAsync(buffer, 0, buffer.Length).ContinueWith((task) =>
{
stream.Close();
listener.Stop();
});
string error = context.Request.QueryString["error"];
if (error != null)
return;
string state = context.Request.QueryString["state"];
if (state != request.State)
return;
string code = context.Request.QueryString["code"];
await APIController.GoogleLogin(request, code, (success, resultObject) => {
if (!success) {
//Handle all request errors (username already exists, email already exists, etc)
} else {
((App)Application.Current).UserSettings.Email = resultObject["email"].ToString();
((App)Application.Current).SaveSettings();
}
attemptingLogin = false;
});
}
and
public static GoogleOAuthRequest BuildLoopbackRequest(params string[] scopes) {
var request = new GoogleOAuthRequest {
CodeVerifier = RandomDataBase64Url(32),
Scopes = scopes
};
string codeChallenge = Base64UrlEncodeNoPadding(Sha256(request.CodeVerifier));
const string codeChallengeMethod = "S256";
string scope = BuildScopes(scopes);
request.RedirectUri = string.Format("http://{0}:{1}/", IPAddress.Loopback, GetRandomUnusedPort());
request.State = RandomDataBase64Url(32);
request.AuthorizationRequestUri = string.Format("{0}?response_type=code&scope=openid%20profile{6}&redirect_uri={1}&client_id={2}&state={3}&code_challenge={4}&code_challenge_method={5}",
AuthorizationEndpoint,
Uri.EscapeDataString(request.RedirectUri),
ClientId,
request.State,
codeChallenge,
codeChallengeMethod,
scope);
return request;
}
To my understanding, from this point the client app has completed the required portion to have the user login to their google account and approve any additional privileges.
Our API/App server is in GoLang.
APIController.GoogleLogin
from above sends the CodeVerifier and AuthorizationCode to the GoLang application server to then finish off the OAuth2 Flow.
Is this the correct flow given our client-server setup?
If so, what is the best practice for the Go Server to retrieve a Access Token/Refresh Token and get user information? Should the client app be performing a looping check-in to the app server as the app server will not immediately have the required information to login?
Thanks for the help!

Firebase: How can i use onDisconnect during logout?

How can i detect when a user logs out of firebase (either facebook, google or password) and trigger the onDisconnect method in the firebase presence system. .unauth() is not working. I would like to show a users online and offline status when they login and out, minimize the app (idle) - not just when the power off their device and remove the app from active applications on the device.
I'm using firebase simple login for angularjs/ angularfire
Im using code based off of this tutorial on the firebase site.
https://www.firebase.com/blog/2013-06-17-howto-build-a-presence-system.html
Please i need help with this!
Presence code:
var connectedRef = new Firebase(fb_connections);
var presenceRef = new Firebase(fb_url + 'presence/');
var presenceUserRef = new Firebase(fb_url + 'presence/'+ userID + '/status');
var currentUserPresenceRef = new Firebase(fb_url + 'users/'+ userID + '/status');
connectedRef.on("value", function(isOnline) {
if (isOnline.val()) {
// If we lose our internet connection, we want ourselves removed from the list.
presenceUserRef.onDisconnect().remove();
currentUserPresenceRef.onDisconnect().set("<span class='balanced'>☆</span>");
// Set our initial online status.
presenceUserRef.set("<span class='balanced'>★</span>");
currentUserPresenceRef.set("<span class='balanced'>★</span>");
}
});
Logout function:
var ref = new Firebase(fb_url);
var usersRef = ref.child('users');
service.logout = function(loginData) {
ref.unauth();
//Firebase.goOffline(); //not working
loggedIn = false;
seedUser = {};
clearLoginFromStorage();
saveLoginToStorage();
auth.logout();
};
The onDisconnect() code that you provide, will run automatically on the Firebase servers when the connection to the client is lost. To force the client to disconnect, you can call Firebase.goOffline().
Note that calling unauth() will simply sign the user out from the Firebase connection. It does not disconnect, since there might be data that the user still has access to.
Update
This works for me:
var fb_url = 'https://yours.firebaseio.com/';
var ref = new Firebase(fb_url);
function connect() {
Firebase.goOnline();
ref.authAnonymously(function(error, authData) {
if (!error) {
ref.child(authData.uid).set(true);
ref.child(authData.uid).onDisconnect().remove();
}
});
setTimeout(disconnect, 5000);
}
function disconnect() {
ref.unauth();
Firebase.goOffline();
setTimeout(connect, 5000);
}
connect();

Connection state with doowb/angular-pusher

I am trying to build an Angular project with Pusher using the angular-pusher wrapper. It's working well but I need to detect when the user loses internet briefly so that they can retrieve missed changes to data from my server.
It looks like the way to handle this is to reload the data on Pusher.connection.state('connected'...) but this does not seem to work with angular-pusher - I am receiving "Pusher.connection" is undefined.
Here is my code:
angular.module('respondersapp', ['doowb.angular-pusher']).
config(['PusherServiceProvider',
function(PusherServiceProvider) {
PusherServiceProvider
.setToken('Foooooooo')
.setOptions({});
}
]);
var ResponderController = function($scope, $http, Pusher) {
$scope.responders = [];
Pusher.subscribe('responders', 'status', function (item) {
// an item was updated. find it in our list and update it.
var found = false;
for (var i = 0; i < $scope.responders.length; i++) {
if ($scope.responders[i].id === item.id) {
found = true;
$scope.responders[i] = item;
break;
}
}
if (!found) {
$scope.responders.push(item);
}
});
Pusher.subscribe('responders', 'unavail', function(item) {
$scope.responders.splice($scope.responders.indexOf(item), 1);
});
var retrieveResponders = function () {
// get a list of responders from the api located at '/api/responders'
console.log('getting responders');
$http.get('/app/dashboard/avail-responders')
.success(function (responders) {
$scope.responders = responders;
});
};
$scope.updateItem = function (item) {
console.log('updating item');
$http.post('/api/responders', item);
};
// load the responders
retrieveResponders();
};
Under this setup how would I go about monitoring connection state? I'm basically trying to replicate the Firebase "catch up" functionality for spotty connections, Firebase was not working overall for me, too confusing trying to manage multiple data sets (not looking to replace back-end at all).
Thanks!
It looks like the Pusher dependency only exposes subscribe and unsubscribe. See:
https://github.com/doowb/angular-pusher/blob/gh-pages/angular-pusher.js#L86
However, if you access the PusherService you get access to the Pusher instance (the one provided by the Pusher JS library) using PusherService.then. See:
https://github.com/doowb/angular-pusher/blob/gh-pages/angular-pusher.js#L91
I'm not sure why the PusherService provides a level of abstraction and why it doesn't just return the pusher instance. It's probably so that it can add some of the Angular specific functionality ($rootScope.$broadcast and $rootScope.$digest).
Maybe you can set the PusherService as a dependency and access the pusher instance using the following?
PusherService.then(function (pusher) {
var state = pusher.connection.state;
});
To clarify #leggetters answer, you might do something like:
app.controller("MyController", function(PusherService) {
PusherService.then(function(pusher) {
pusher.connection.bind("state_change", function(states) {
console.log("Pusher's state changed from %o to %o", states.previous, states.current);
});
});
});
Also note that pusher-js (which angular-pusher uses) has activityTimeout and pongTimeout configuration to tweak the connection state detection.
From my limited experiments, connection states can't be relied on. With the default values, you can go offline for many seconds and then back online without them being any the wiser.
Even if you lower the configuration values, someone could probably drop offline for just a millisecond and miss a message if they're unlucky.

How to alert the user when there's no internet connection

I need to alert the user with the following conditions;
Request timed out
No internet connection
Unable to reach the server
Here's the code; How to capture the following conditions when occurred and alert the user ?
failure: function (response) {
var text = response.responseText;
console.log("FAILED");
},success: function (response) {
var text = response.responseText;
console.log("SUCCESS");
}
I tried the following code to check if the internet is reachable, but it didn't work
var networkState = navigator.network.connection.type
alert(states[networkState]);
if (networkState == Connection.NONE){
alert('No internet ');
};
UPDATE **
I added the following in my index.html, but, when i disable WIFI, i don't see the alert popping.
<script>
function onDeviceReady() {
document.addEventListener("offline", function() {
alert("No internet connection");
}, false);
}
</script>
The best thing to do is to listen to the "offline" event. When you get the offline event you can warn your user and take whatever steps necessary to save data, etc.
For instance, your "deviceready" callback:
document.addEventListener("offline", function() {
alert("No internet connection");
}, false);
This code should work for most all versions of PhoneGap. It's been in since at least the 1.0 release.
Exactly as Simon said, you can use
document.addEventListener("offline", youCallbackFn, false);
or you can interrogate the boolean property
navigator.onLine
(Should return true or false)
However, this technique will tell you whether device is connected. The caveat is such that device can be connected to WiFi, but the router might be offline. In that case, use a polling mechanism, like timely Ext.Ajax.request with lower timeouts. Timeout expired = offline.
You can use PhoneGap's NETWORK API
The network object gives access to the device's cellular and wifi connection information.
You can test it in the following way,
function onDeviceReady() {
navigator.network.isReachable("phonegap.com", reachableCallback, {});
}
// Check network status
//
function reachableCallback(reachability) {
// There is no consistency on the format of reachability
var networkState = reachability.code || reachability;
var states = {};
states[NetworkStatus.NOT_REACHABLE] = 'No network connection';
states[NetworkStatus.REACHABLE_VIA_CARRIER_DATA_NETWORK] = 'Carrier data connection';
states[NetworkStatus.REACHABLE_VIA_WIFI_NETWORK] = 'WiFi connection';
alert('Connection type: ' + states[networkState]);
}
You can add 'Ext.device.Connection' in app.js of your application. And check your device is online or offline using code:
if (Ext.device.Connection.isOnline()) {
alert('Connected to internet');
}
else{
alert('You are not connected to internet');
}
Just Embed this in your tag
<body onoffline="alert('PLEASE CHECK YOUR INTERNET SETTING');">

Resources