Jump to content

Passing client's apparent public IP to uniGUI session on Login button click


wprins

Recommended Posts

Hi,

 

Problem:

I'm trying to determine the client's apparent IP address (their public IP) so it is known inside the user's uniGUI session.  

 

Background:

This is needed to enable us to generate an access token for integrating with an external party/site, where the originating browsers IP address is also used in the token signature/hash calculation/verification process.

 

Obviously determining the user's IP is something that needs to happen inside the browser itself, in order to get the apparent public IP address of the browser running the application.  

 

Now it turns out that from a web browser/JS perspective this is quite easy.  In fact there are multiple services that has API's that enable one to retrieve your apparent public IP.  (See here, for example.)  

 

So the obvious idea is to somehow have the browser perform this IP capture itself just prior to, or as part of Login and then pass it and store it as part of the user's session (MainModule).

 

Now I've had a look at the "HTTP POST callback" examples which would've provided, it would seem,a way to achieve this, if our login page was in fact a TUniURLFrame.  I could then write some Javascript code to GET from the above URL (on document ready/loaded etc, say) and then update the browser document accordingly to finagle things so that on submit/POST the IP would effectively get passed together with the other form variables.    

 

However, we currently use a typical uniGUI login form with edit boxes and so on for login, not a uniURLFrame.  So I'm a little at a loss as to where/how to sneak the required JS into the page to fetch the IP and ensure that it gets passed to the uniGUI server session either immediately or on login. 

 

Question:

Given the above, what's the best way for me to effectively get the browser to get the user's IP address using e.g. https://api.ipify.org/?format=json, and pass this back with the other login details on login to the uniGUI server session?

 

Alternatively do you have any better ideas or have I missed some obvious solution to this problem?  (Maybe perhaps using UniSession.AddJS() which has just occurred to me while writing this...?)

 

Thanks so much in advance for any pointers/suggestions,

 

Walter

 

 

 

 

Link to comment
Share on other sites

 

 

Hi,

 

If I understand correctly,

you can use these properties for this:

UniApplication.RemoteAddress
UniSession.RemoteHost
UniSession.RemoteIP

Best regards,

 

Hello!

 

Thanks for your response, but this does not help unfortunately.  The properties you gave gives the "local network" IP address of the client machine on which the browser is running, which isn't usually the same as the apparent public IP address of that same machine.

 

For example, if I run the uniGui server on my own machine and visit the server page with a browser, the above properties predictably return 127.0.0.1.  If I visit my machine from another machine on the LAN, these properties give the the other machine's LAN IP address.  So far so good.  

 

But of course, if my machine or the other machine, were to visit some other website out on the internet, then both my machine, and the other machine will appear to be originating from a third different IP address, e.g the public IP address of the router and/or proxy server through which the traffic is being routed from the machines out to the site being visited.   

 

Now if you think back to what I'm doing:  The client browser is simultaneously showing a (local network) uniGUI server, *and* framing another site (out on the internet in this case).  Therefore, to the UniGUI server the browser machine appears to have a local LAN IP, but to the site on the internet the browser looks like it has the public IP address where the traffic is coming from.  Now for the framing to work, the uniGUI server has to know what the browser's apparent IP address is, and generate an access token using this information (amongst other things.)  E.g. it doesn't use the the local LAN IP that is directly visible to the UniGUI server and is obviously not known by the remote site, but it has to use the IP address seen by the third party site.  As I mentioned before, this can in fact be easily retrieved from the context of the client browser with a bit of Javascript, but I'm not sure how to get this back to the uniGUI server.   That is, my key question is what the best way is to essentially get the browser to do a request to the internet (to establish its "public" IP) and then pass this to the user's UniGUI session,  so it can generate the token to place in a TUniURLFrame.

 

Thanks in advance!

 

Walter

Link to comment
Share on other sites

  • 3 weeks later...

Hello, I've been away on holiday.  Unfortunately I see no one's got any suggestions for my problem?

 

So hence I post this additional response to bump it up a bit.

 

As a reminder, my problem/question in short:  

 

What is the best way to call/run some Javascript in the browser and have something from it posted back to the corresponding UniGUI user session, and then from the UniGUI session update or set a cookie in the browser as a result?  

 

Walter

Link to comment
Share on other sites

  • 2 weeks later...

Hi Walter

 

I was exploring this for very similar reasons.

 

I did look into Java solutions, to no avail, but what I did in the end was to just use the UniGUI version of the Indy TIdHTTP component (uIdHTTP). Using it on the client side in the Login form creation event.

sExtIPAddress := HTTP.Get('http://checkip.amazonaws.com');

I do use a few sites to check the address like "http://ipecho.net/plain"as well. Pretty basic and I'm not too sure of the downside of doing it this way but it seems to work for the moment at least.

 

I'd be interested to know if you or anyone has any alternate solutions to this?

 

Mark

Link to comment
Share on other sites

"As I mentioned before, this can in fact be easily retrieved from the context of the client browser with a bit of Javascript, but I'm not sure how to get this back to the uniGUI server. 

 

 

 

Walter just send an Ajax request back to the MainForm and handle it in the OnAjaxEvent event?

 

ajaxRequest(MainForm, 'ClientIPAddr', [ip=192.168.1.1])

Link to comment
Share on other sites

Walter this will achieve what you are looking for. Just remember that the Login Form might close before the ajaxEvent has been handled so you should choose where you want to inject the JS code.

 

I have attached a sample project as well.

procedure TfrmLogin.btnLoginClick(Sender: TObject);
begin
  UniSession.AddJS('$.getJSON(''//freegeoip.net/json/?callback=?'', function(data) {' +
                   'ajaxRequest(' + Self.WebForm.JSName + ', "ClientIPAddr", ["ip="+data.ip]);});');
end;				 
	
procedure TfrmLogin.UniLoginFormAjaxEvent(Sender: TComponent; EventName: string;
  Params: TUniStrings);
begin
  if SameText(EventName, 'ClientIPAddr') then
    ShowMessageN(Params.Values['ip']);
end;

ClientPublicIP.zip

  • Upvote 1
Link to comment
Share on other sites

  • 2 months later...

Gerhard, sparkz thanks. 

 

I've not been on the forums much for the last 2 or so months.  I eventually actually came up with a solution by myself about 2 months ago. It's not entirely unlike what you've (Gerhard) done, yours is a bit more succinct.  I was planning on posting my solution at some point but have been either away or too busy.  I'll still post it sometime as I avoid using AddJS which seems somehow slightly smelly to me and so may be of interest to others...(?)   

 

Edit:

 

Gerhard, thanks again for your example.  I did just have a quick look at what I did previously and I think your solution is perhaps preferable, nice and neat and to the point.  Will try it out in due course.

 

Nevertheless, for interest and in case anyone finds it useful or educational: Basically I used UniSession.CallbackURL() and UniSession.CallbackTarget() to generate a callback URL and target from within Delphi code. 

 

These are placed inside static HTML+JS page code placed a designtime (e.g. TUniHTMLFrame or TUniURLFrame content). 

 

At the bottom of the page I wrote some Javascript to retrieve the IP, after which I trigger a normal JS Form submit which fires the retrieved IP address off into the UniGui Session via UniFormAjaxEvent().

 

UniHTMLFrame1.HTML content:

<div style="background-color:#ccc">
<br/><br/><br/><br/><br/>
<form name="input" action="{URL_CALLBACK}" method="POST" target="{CALLBACK_TARGET}">
Username: <input type="text" name="user" value="Enter Text..."><br/>
IP:<input type="text" name="ip" id="ip" value=""><br/>
<input type="submit" value="Submit">
</form>
<br/><br/><br/><br/><br/>
</div>
<script>
  var request = new XMLHttpRequest();
  request.open('GET', 'https://jsonip.com', false); //synchronous
  request.send(null);
  if(request.status === 200) {
      data = JSON.parse(request.response);
      //console.log(data);
      //JQuery way: $("#ip").val(data.ip);
      document.forms["input"]["ip"].value = data.ip;
      //JQuery way: $("form#input").submit();
      document.forms["input"].submit();    
  }
</script>

On Form create:

procedure TMainForm.ReplaceTags;
var
  S, Sc : string;
begin
  S := UniSyntaxEdit1.Text;

  Sc := UniSession.CallbackUrl('mycallback', Self, []);
  S := StringReplace(S, '{URL_CALLBACK}', Sc, []);

  Sc := UniSession.CallbackTarget;
  S := StringReplace(S, '{CALLBACK_TARGET}', Sc, []);

  UniHTMLFrame1.HTML.Text := S;
end;
procedure TMainForm.UniFormCreate(Sender: TObject);
begin
  UniSyntaxEdit1.Text:=UniHTMLFrame1.HTML.Text;
  ReplaceTags;
end;

Form Ajax event handler:

procedure TMainForm.UniFormAjaxEvent(Sender: TComponent; EventName: string;
  Params: TUniStrings);
begin
  if EventName = 'mycallback' then
  begin
    UniEdit1.Text := Params.Values['user'];
    UniEdit2.Text := Params.Values['ip'];
    UniMemo1.Text := Params.Text;
  end;
end;

(Again, this was based on and is a modified version of "HTTP Post Callback - HTMLFrame" demo project.  I also similarly modified "HTTP Post Callback - URLFrame - Auto Target" which uses TUniURLFrame component instead of TUniHTMLFrame and does not require the "CALLBACK_TARGET" substitution.)

 

Best regards.

Link to comment
Share on other sites

  • 6 months later...

For anyone finding this in future:  The URL suggested by Gerhard (freegeoIP) is being retired as of July 2018.  An alternative is www.ipify.org.  Code as follows:

 

procedure TLoginForm.UniLoginFormAjaxEvent(Sender: TComponent;
  EventName: string; Params: TUniStrings);
begin
  if SameText(EventName, 'ClientIPAddr') then
  begin
    //Do what you want with the IP.  As example we set the IP on a frame embedded in the login form (assumes there's a BrowserIP property.)
    LoginFrame.IPLabel.Caption := 'Your public IP is: '+Params.Values['ip'];
    LoginFrame.BrowserIP := Params.Values['ip']; 
  end;
end;
procedure TLoginForm.UniLoginFormBeforeShow(Sender: TObject);
begin
  //Reference: https://www.ipify.org/
  UniSession.AddJS(
    '$(function() {'+
    '  $.getJSON("https://api.ipify.org?format=jsonp&callback=?",'+
    '    function(json) {'+
    '      ajaxRequest(' + self.WebForm.JSName + ', "ClientIPAddr", ["ip="+json.ip]);'+
    '    }'+
    '  );'+
    '});'
    );
end;
Link to comment
Share on other sites

To get the public IP I call a huge php file on my own server.

It was years in the making, extremely optimized,

especially the return line.

<?php
  echo $_SERVER['REMOTE_ADDR'];
  return 200;
?>
Link to comment
Share on other sites

  • 1 year later...

Hi,

I am currently using UniSession.RemoteIP to obtain the ip of the sessions of the users that enter my application, however there is a firewall in the middle and UniSession.RemoteIP is registering the ip of the firewall and not of the sessions of each user.

Is there any way to get it ip from each user's session?

Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...