Capturing Data of a User Visiting my website - django

How can I capture data of someone visiting my website via a shortened link? I want to be able to capture the OS, IP, divide ID etc. Would capturing the user agent string be the best option? What are some other ways? In my case I'm building a website with DJAGNO.

To get the IP, you can use the HTTP_X_FORWARDED_FOR or REMOTE_ADDR headers from request.META
For instance:
FORWARDED_HEADER = "HTTP_X_FORWARDED_FOR"
REMOTE_HEADER = "REMOTE_ADDR"
headers = request.META
ip_header = FORWARDED_HEADER if FORWARDED_HEADER in headers else REMOTE_HEADER
ip_address = headers.get(ip_header)
For the user agent you can use the HTTP_USER_AGENT header:
USER_AGENT_HEADER = "HTTP_USER_AGENT"
user_agent = request.META.get(USER_AGENT_HEADER)

Related

cpprestsdk http_listener ignoring everything after #

EDIT: See my post below for answer how to fix this.
I am building a client app that will store some data in the user dropbox app folder. So currently I am using implicit grant that will redirect the user to the given redirect uri with the parameters passed after the # in the url
Example:
localhost:1666/Dropbox#access_token=...&token_type=.......
Creating a http listener over the localhost url it detects the request however everything after # is ignored and is not passed as part of the request. Is there a way to make capture the data after the #, or is there any other library that allows me to do so?
I am using the cpprestsdk https://github.com/microsoft/cpprestsdk
web::http::experimental::listener::http_listener* l = new web::http::experimental::listener::http_listener(m_authConfig.redirect_uri());
l->support([this](web::http::http_request request) -> void
{
auto uri = request.request_uri();
auto requestPath = web::uri::split_path(uri.path());
auto queryObjects = web::uri::split_query(uri.query());
auto s = uri.fragment();
if (request.request_uri().path() == U("/Dropbox")) && request.request_uri().query() != U(""))
{
request.reply(web::http::status_codes::OK, U("ok.") + uri.query());
}
else
{
request.reply(web::http::status_codes::OK, U("error.") + uri.query());
}
});
l->open().wait();
Thanks!
So after researching a bit, it turns out that # (fragments) are not sent back in most browsers, so to be able to get the data i return the following java-script script:
<script> window.location.replace([location.protocol, '//', location.host, location.pathname, '?', location.hash.substring(1,location.hash.length )].join(''));</script>
This will convert the hash part to a query string and redirect it the user to it so that the listener detects it.

Make post request with separate hostname and url in python

I am trying to make a request.post(someURL) where the host name is not the same as the url.
The host I am trying to reach is in a private cluster but is accessible from a public URL. The problem is when I make a normal post request I get a 404 response because the host is expecting its internal name (hostName).
Is there a way to do something like response = request.post(someURL, hostname = hostName, data = data) so the request will go to someURL but give hostName as the host name instead of someURL.
"hosts" are almost always passed in the header. try something like this
#add/remove whatever other headers you need
headers={
'Accept':'application/json, text/plain, */*',
'Accept-Encoding':'gzip, deflate, br',
'Accept-Language':'en-US,en;q=0.9',
'Host':'hostName'
}
response = request.post(someURL, headers=headers, data = data)
Note you may want to check the request as some sites require a Host, Origin, Referer, etc.

Unable to relay recipient in non-accepted domain

All emails with the domain #mycompany.com are sent successfully. But, if MantisBT wants to send an email to anyone else, for example #othercontractor.com, or #gmail.com, etc , the email is not sent.
In addition, a collateral damage of this problematic email is that it will get stuck in "MySqlDatabase/mantis_email_table" and all the emails after this problematic email in that table won't be sent. So, to fix it, I have to manually delete that entry in the table. It is not very convenient when I want to add contractor who has his own email domain in our bug tracker.
This the email configuration in: /path_to_mantis_bt/config/config_inc.php
// Email Configuration
$g_email_send_using_cronjob = ON;
$g_allow_signup = ON; //allows the users to sign up for a new account
$g_enable_email_notification = ON; //enables the email messages
$g_phpMailer_method = PHPMAILER_METHOD_SMTP;
$g_smtp_host = 'edge.mycompany.com';
$g_smtp_connection_mode = '';
$g_smtp_port = 25;
$g_administrator_email = 'myname#mycompany.com';
$g_from_email = 'myname#mycompany.com';
$g_return_path_email = 'myname#mycompany.com';
$g_from_name = 'Mantis Bug Tracker';
I should mention that we are hosting MantisBT on our own server Microsoft Server 2012 R2 and WAMP(latest version).
The error: 2018-01-08 10:24 PST MAIL email_api.php:1379 email_send() ERROR: Message could not be sent - SMTP Error: The following recipients failed: xxx#gmail.com: 5.7.54 SMTP; Unable to relay recipient in non-accepted domain
It's working now, but I used sendmail instead of using the WAMP/SMTP.
To install SENDMAIL on WAMP, I followed these instructions
This the email configuration in: /path_to_mantis_bt/config/config_inc.php
$g_allow_signup = ON; //allows the users to sign up for a new account
$g_enable_email_notification = ON; //enables the email messages
$g_phpMailer_method = PHPMAILER_METHOD_SENDMAIL; //If not using sendmail, use: PHPMAILER_METHOD_SMTP;
$g_smtp_host = 'edge.mycompany.com';
$g_smtp_connection_mode = 'tls';
$g_smtp_port = 587;
$g_smtp_username = 'xxx'; // my username for email myname#mycompany.com
$g_smtp_password = 'xxx'; // my password for email myname#mycompany.com
$g_administrator_email = 'myname#mycompany.com';
$g_webmaster_email = 'myname#mycompany.com';
$g_from_email = 'myname#mycompany.com';
$g_return_path_email = 'myname#mycompany.com';
$g_from_name = 'Mantis Bug Tracker';
// Log configuration
$g_log_level = LOG_EMAIL | LOG_EMAIL_RECIPIENT | LOG_FILTERING | LOG_AJAX;
$g_log_destination = 'file:/wamp64/logs/mantis.log';
?>
IF you follow the link above, you will know how to update php.ini and sendmail.ini . Update these 2 files with the information in config_inc.php.
I had the same issue. In my case, we were sending out emails from an application and there was a user bcced (hardcoded in the code) which was not in the domain and hence it failed
I had same issue once I changed to #newdomain.com.
In my case I found suggestion on the web to clear cache of my browser. I did and all start working.
Basically, you need to reload all config files from scratch with new globals...
At least it worked for me.
Cheers.

Q: Converting hostname to IP from a dictionary for netmiko connection?

In the past, I was able to do something simple like this to read a file
of IP addresses that I would iterate through to SSH to each one
# Grab the list of devices from a text file
devices = open('./devices.txt','r').read().split('\n')
# Connect to each router and do a show run command
for device in devices:
net_connect = ConnectHandler(device_type="cisco_ios", ip=device, username="myusername",
password=password)
This time, however, I need to do something a bit more complex.
I pull some data from a JSON source where I can derive a "hostname."
But I cannot connect to the "hostname." If the hostnames were in DNS
that would be easier but sadly they are not.
So.. I have a list of hosts to IPs that I figured I could use and pull
into a dictionary.
But now I somehow need to match up the hostname that gets derived from
the JSON data to match against a switchname in the hosts.csv so that I can
then basically convert hostname to IP so that I can then iterate through each
device in devices to SSH into each one.
This is all I have so far. I'm stuck at this point. Not sure how to match
things up to get the IP to use in my net_connect statement.
# Creat dict mapping hostnames to IP address for devices
with open(r'hosts.csv', 'r') as f:
for line in f:
switch = {}
switch_line = line.split(',')
switch = {
'ip': switch_line[1],
'switchname': str(switch_line[0]).strip('\n')
# Define list of devices to connect to and the config changes to be made
pa = []
# This data is coming from a JSON source
for device in devices:
if device['switchParent']:
hostname = device['switchParent']
else:
hostname = device['destDevice']
# hostname technically is the device I need to connect
# however it needs to resolve to an IP from the switch dict earlier
net_connect = ConnectHandler(device_type="cisco_ios", ip=hostname,
username="myusername", password=password)
Assuming that switchname has a unique ip address then you should parse the hosts.csv file this way:
# Create dict mapping hostnames to IP address for devices
switch = {}
with open(r'hosts.csv', 'r') as f:
for line in f:
switch_line = line.split(',')
switch[str(switch_line[0].strip())] = switch_line[1]
Then you go through the JSON data source:
# This data is coming from a JSON source
for device in devices:
if device['switchParent']:
hostname = device['switchParent']
else:
hostname = device['destDevice']
# hostname technically is the device I need to connect
# however it needs to resolve to an IP from the switch dict earlier
net_connect = ConnectHandler(device_type="cisco_ios", ip=switch[hostname],
username="myusername", password=password)
That should work IF hostname is expected to be one of the keys from the switch dict.

get_host() vs META['REMOTE_ADDR'] for security reasons

I am working on a Django project where users will have custom info given to them depending on their location. In order to do this, I use their IP address to identify their country. In order to keep data in the database consistent, I need to make sure I have an accurate IP.
I understand that using META usually uses headers sent by the client's browser, but I don't know if that applies to the REMOTE_ADDR attribute.
TLDR: what is the difference between HttpRequest.get_host() and HttpRequest.META['REMOTE_ADDR']?
The difference between HttpRequest.get_host() and HttpRequest.META['REMOTE_ADDR'] is that the first one checks IP in the following headers in order of decreasing preference:
HTTP_X_FORWARDED_HOST
HTTP_HOST
SERVER_NAME combined with SERVER_PORT
whereas the second one check the IP in the header REMOTE_ADDR.
There is a huge difference in the type of information returned: get_host() will give you the name of the server hosting your application, not the IP of the client.
More in detail, here is the implementation of get_host():
def get_host(self):
"""Returns the HTTP host using the environment or request headers."""
# We try three options, in order of decreasing preference.
if settings.USE_X_FORWARDED_HOST and (
'HTTP_X_FORWARDED_HOST' in self.META):
host = self.META['HTTP_X_FORWARDED_HOST']
elif 'HTTP_HOST' in self.META:
host = self.META['HTTP_HOST']
else:
# Reconstruct the host using the algorithm from PEP 333.
host = self.META['SERVER_NAME']
server_port = str(self.META['SERVER_PORT'])
if server_port != ('443' if self.is_secure() else '80'):
host = '%s:%s' % (host, server_port)
allowed_hosts = ['*'] if settings.DEBUG else settings.ALLOWED_HOSTS
domain, port = split_domain_port(host)
if domain and validate_host(domain, allowed_hosts):
return host
else:
msg = "Invalid HTTP_HOST header: %r." % host
if domain:
msg += "You may need to add %r to ALLOWED_HOSTS." % domain
raise DisallowedHost(msg)
If you want to check for client IP address, here are some headers that could be worth checking (see Getting the client IP address: REMOTE_ADDR, HTTP_X_FORWARDED_FOR, what else could be useful?):
REMOTE_ADDR
HTTP_X_FORWARDED_FOR
HTTP_CLIENT_IP
HTTP_X_FORWARDED_FOR can be comma delimited list of IPs
HTTP_X_FORWARDED
HTTP_X_CLUSTER_CLIENT_IP
HTTP_FORWARDED_FOR
HTTP_FORWARDED
If you don't know which one to pick (if not all), you could log those headers and pragmatically add new checkings over time.