Best way to secure an API key in Vanilla JS and Django - javascript

I am building a simple webapp in Django which makes use of Google Places API. The API is called from main.js file, and the data is displayed on the page.
Right now, the main.js file looks like this:
...
const apikey_gmaps = "AIzaSyDMjUwEt0bumPTVt1GpfQHrxyz";
var lat = position.coords.latitude;
var long = position.coords.longitude;
fetch("https://maps.googleapis.com/maps/api/geocode/json?latlng="+lat+","+long+"&key="+**apikey_gmaps**)
.then(...
...
I want to secure the API key, since I don't want everyone to be use and share my credentials, and break my bank. I have been reading about it lately, and I am able to use .env file in Django(Python) using the Decouple library. I want to use the .env variables in the main.js file. The only solution that I could find was to use dotenv, but that requires NodeJS.
Is there any way to pass the API key from .env to Django and then from Django to main.js? Is there a better way of achieving this?

You can't secure it if you are calling it from the client-side. What you need to do is create a view to abstract the key.
In views.py:
from rest_framework.decorators import api_view, renderer_classes
from rest_framework.renderers import JSONRenderer, TemplateHTMLRenderer
from rest_framework.response import Response
import requests
#api_view(('GET',))
#renderer_classes([JSONRenderer])
def gmapAPI(request):
lat = request.GET.get('lat', 'default_fb_value')
long = request.GET.get('long', 'default_fb_value')
apikey_gmaps = "#KEY_OR_GET_FROM_ENV";
url = f'https://maps.googleapis.com/maps/api/place/nearbysearch/json?location={lat},{long}&rankby=distance&key={apikey_gmaps}'
r = requests.get(url)
print(r.json())
return Response(r.json())
In urls.py add:
...
path('maps_api/', views.gmapAPI, name='maps_api'),
...
In main.js:
...
var lat = position.coords.latitude;
var long = position.coords.longitude;
var targetUrl = (`website/maps_api/?lat=${lat}&long=${long}`)
fetch(targetUrl)
.then(...
...
Please note that this will make the process of digging up the key very difficult, but the key will still be discoverable, and a good/bad hacker can still get it.

Related

Birt with restful APIs

I am developing BIRT reports for a PHP project. I can easily develop reports by connecting directly to the database using JDBC Datasource. However certain data come from restful api and I am unable to create a datasource from those api endpoints.
Birt has option to create datasource from web services, however this seems to only accept SOAP APIs. I was wondering if someone can show me how to create birt datasources from REST APIs. I read through all the search results provided by google. Some recommend using POJO Datasource, while some recommend using scripted Datasource which requires knowledge in Java and which is little difficult for a PHP programmer to crack through. Most links redirect to devshare which now points to open text and the content doesnot exist anymore. I tried all the recommendations which are as follows.
Using Webservices Datasource: It requires the location of wsdl file which is not there for a REST API. It comes only with SOAP API. Would be great if there is an alternative to this.
Tried POJO Datasource and Scripted Datasource: But as a PHP developer couldn't get a good result as there is no step by step guide out there to do this.
Because REST is pretty popular today, I was wondering if there is any straight forward way to do this, or if there is anyone who can help with Java or Javascript program for scripted datasource for a PHP head. I have been trying this for the last 15 days and is desperate for some help.
Ended up with scripted datasource.
Create a scripted datasource with open() method as follows:
logger = java.util.logging.Logger.getLogger("birt.report.logger");
importPackage(Packages.java.io);
importPackage(Packages.java.net);
//if you have a parameter
var param= params["industryname"].value;
var inStream = new
URL("http://yourapi/endpoint/" + param).openStream();
var inStreamReader = new InputStreamReader(inStream);
var bufferedReader = new BufferedReader(inStreamReader);
var line;
var result = "";
while ((line = bufferedReader.readLine()) != null)
result += line;
inStream.close();
var json = JSON.parse(result);
vars["HTMLJSON"] = json;
logger.warning (result);
//logger.warning (json);
Then create a dataset with the following methods:
open()
recNum=0;
fetch()
len = vars["HTMLJSON"].length;
if (recNum >= len)
return false;
row["name"] = vars["HTMLJSON"][recNum].name;
row["id"] = vars["HTMLJSON"][recNum].id;
row["active"] = vars["HTMLJSON"][recNum].active;
recNum++;
return true;
You may need Apache Commons IO included in your scriptlib folder.

Django/AngularJS: How do I access my Python Context Items from my AngularJS Script

Good day SO! I am a beginner thats trying out a Django Project while using AngularJS for my frontend Firebase chat system. Here is a previous question that I asked regarding this project: Firebase/Angular: Messages not showing in HTML, but contain the message objects
I know that it is not wise to use json variables on your html directly while using django/python, but it just so happens that my firebase chat module is using angularJS (and I do not know how to code this chat function in django..), and my angularJS code requires access to my Django's context querysets from View.py.
Is there any way that I can either:
Push json items into my HTML/Template the same way I push context
information into my HTML/Template from Views.py and use it in my
AngularJS Script?
Access my Django/Python's data sets from Context from Views.py?
Here is my AngularJS code for firebase:
var app = angular.module('chatApp', ['firebase']);
app.controller('ChatController', function($scope, $firebaseArray) {
//I want to populate the crisis and sender variables with something from my context
//from Views.py.. Inside planList
var crisis = "Crisis1";
var sender = "Sender1";
//Query
var ref = firebase.database().ref().child(crisis).child('CMO-PMO');
$scope.messages = $firebaseArray(ref);
$scope.send = function() {
$scope.messages.$add({
sender: sender,
message: $scope.messageText,
date: Date.now()
})
}
})
And here is my Views.py Code:
def home(request):
template = loader.get_template('app/home.html')
planList = Plan.objects.filter(plan_crisisID__crisis_status='Ongoing')
context = {
'planList': planList
}
return HttpResponse(template.render(context, request))
Both variables needed in my AngularJS code (crisis and sender) are from the planList context.
Is there any way for me to achieve this? Please give me some assistance.. Thank you so much and I greatly appreciate it :) I will gladly provide any additional information if needed, and will reply promptly too!
I think it's better to use an API for it. You can create an API using DRF very easily. For example:
# Serializer
class SomeSerializer(serializers.ModelSerializer):
class Meta:
model = Plan
fields = ('model_fields',)
# Views:
from rest_framework import generics
Class SomeView(generics.ListView):
queryset = Plan.objects.all()
serializer_class = SomeSerializer
# urls
url(r'^plans$', SomeView.as_view()),
In Angular JS, if you use angular-resource, you can simply get the data by:
res = $resource('/plans')
res.query().$promise.then(function(data) {
console.log(data)}, // You get your data in here
function(error) {
console.log(error)}
)

How to call a file in controller

I have a file in which ii declared my videouploadfolder url and i want to call that file in my js
my config.js
var filepath = {
uploadVideoUrl : './public/videos'
}
I called it in my node.js as
var config = require(config);
config.uploadVideoUrl;
But i am not sure how to call in js,can anyone suggest help please.Thanks.
With angularjs you can make use of constant,
var app = angular.module('configuration', [])
.constant('uploadVideoUrl', './public/videos')
Then you can use in your controller as,
app.controller('Ctrl1', ['$scope','uploadVideoUrl'
function ($scope,'uploadVideoUrl') {
var config = uploadVideoUrl;
}
]);
If you want your config.js file to stay only in server where you have ther services editing it, then you would have to write a REST route in nodeJs to fetch the content of the config and send it back to angularJS client.
If you dont mind saving that config json in your client side itself instead of your server then follow what Sajeetharan has said.

hard code SLACK_API_TOKEN into javascript code

using https://www.npmjs.com/package/slack-client
expects you to make an extra file just for the token and to get it you must do
process.env.SLACK_API_TOKEN
I don't like this approach of creating a file just for the sake of a token!
My code is server side, already in a directory that users cannot see so I would like to just write the token into the javascript as an object/string/array
I have so far failed with array
var token=[
'SLACK_TOKEN=xxxx'
, 'SLACK_CLIENT_ID=xxxx'
, 'SLACK_CLIENT_SECRET=xxxx'
];
and string
var token=
'SLACK_TOKEN=xxxx\n'
+ 'SLACK_CLIENT_ID=xxxx\n'
+ 'SLACK_CLIENT_SECRET=xxxx'
;
and object
var token={
SLACK_TOKEN:'xxxx'
, SLACK_CLIENT_ID:'xxxx'
, SLACK_CLIENT_SECRET:'xxxx'
};
Everyone else's apis just get you to put things like secret keys inside srings or objects like normal! How can I do this the normal way?
process.env.SLACK_API_TOKEN isn't a file, it's an environment variable. The advantage of keeping your API key there is that you can't accidentally commit it to version control. That said, the page you linked to makes it pretty clear that you don't have to use it:
var RtmClient = require('slack-client').RtmClient;
var token = process.env.SLACK_API_TOKEN || '';
var rtm = new RtmClient(token, {logLevel: 'debug'});
rtm.start();
Just set the token variable to your API token, then pass it as the first parameter to new RtmClient():
var RtmClient = require('slack-client').RtmClient;
var token = 'YOUR SLACK API TOKEN';
var rtm = new RtmClient(token, {logLevel: 'debug'});
rtm.start();

Serve dynamic javascript file with nodejs

Questions
How to serve javascript file dynamically? Specifically, the scripts maintain most of its body but with some variables changable (imagine HTML Jade template, but this is for pure javascript).
Scenario
When user or browser (http GET in general) visits /file.js passing parameter api, e.g. /file.js?api=123456, I would like to output pure javascript where I can take that 123456 and put in inside of my code, dynamically. Content-Type is application/javascript.
Sample:
var api = #{req.query.api}; //Pseudo
//The rest of my javascripts template
...
From my main .js file, I have set up the route:
app.get( '/file.js', function( req, res ) {
//Pseudo code that I would like to achieve
var name = req.query.name;
res.render( 'out_put_javascript_file_from_jade_file.jade', { name: name } );
});
So when a person visits /file.js, the script file will be rendered differently based on the parameter api passed in the URL. The only possible dynamic way I can think of is using Jade, but it doesn't allow pure javascript template. I believe there must be other solutions.
Please excuse my explanation. The problem is somewhat like this: How to generate a pure JavaScript file with Jade
If you want to do something quick and dirty, then you can do something like this (based on your example in the comments).
App init - read the .js template file and cache it:
// this should be async, but hey, not teaching you that part here yet
var fileJs = fs.readFileSync('file.js.template');
File.js:
(function() {
$(window).on('load', function() {
alert('Your api key is API_KEY_CONST');
});
})();
Request:
GET /api/file.js?key=123
Router:
app.get('/api/file.js', function(req, res) {
var key = req.query.key;
var key = fetchKeyFromDBSync(); // just to make it easier here, no async.
var out = fileJs.replace(API_KEY_CONST, key);
res.setHeader('content-type', 'text/javascript');
res.write(out);
res.end();
});
Now, this is really dumb and you should not try it at home, but it simply demonstrates how to do what you wanted.
Edit:
Depending on the file length, you might perform a bit better if you put the chunks of the file into an array, like:
var fileChunks = ['(function(){ blablabla;', 'var myAPIKey=', 'KEY_PLACEHOLDER', '; alert (myAPIKey);', '})()']
So later when you're resolving it with the real API key, you join the file.
fileChunks[2] = '12345';
var responseData = fileChunks.join('');
res.write(responseData);
But your last-accessed api key is then held in an array. Not quite future proof, but it shouls work if you need something quick.

Categories

Resources