Removing image accessibility - javascript

I have a web page that is feed from flask a link to a picture. I have it so the image disappears after a second or two. However, if you look at the page source you can still get the picture, via finding the exact url for the picture. How do I remove access to the url or remove the picture from the url so that the user can no longer view the image after it disappears.
Html Page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Welcome</title>
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
</head>
<body>
<script type="text/javascript">
$(document).ready(function () {
var c = document.getElementById('image');
console.log(typeof(c));
setTimeout(function () {
$('#des').css('visibility', 'hidden');
}, 1750);
fs.unlink("{{ url_for('static', filename = '1l1l1lI1lIlIlIlI1IlI1II1l1.jpg') }}");
removeElement(c)
storage.clear(c);
sessionStorage.clear(c);
});
</script>
<div id="des">
<img id="image" src="{{ url_for('static', filename = '1l1l1lI1lIlIlIlI1IlI1II1l1.jpg') }}"/>
</div>
</body>
</html>
main.py
from datetime import datetime
from flask import make_response
from functools import wraps, update_wrapper
from flask import Flask, request, session, g, redirect, url_for, abort, \
render_template, flash
app = Flask(__name__) # create the application instance
app.config.from_object(__name__) # load config from this file , flaskr.py
def nocache(view):
#wraps(view)
def no_cache(*args, **kwargs):
response = make_response(view(*args, **kwargs))
response.headers['Last-Modified'] = datetime.now()
response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0, max-age=0'
response.headers['Pragma'] = 'no-cache'
response.headers['Expires'] = '-1'
return response
return update_wrapper(no_cache, view)
#app.route(r'/')
#nocache
def landingpage():
return render_template('index.html')
if __name__ == '__main__':
app.run()

First and foremost your images won't be protected if the user tries hard enough. You cannot prevent them for taking screen shots or anything of the sort.
There are several ways to help "prevent" them from getting your images:
You can load your image via ajax:
<script>
$('#my_image').attr('src', {{ url_for('image_path') }});
</script>
You can also load via an expiring hash key (database driven). So create a table with a mapping to the file name and then load the image using a route by passing in the hash key. If they try to open the image from a debugger, it can say it was expired and won't load the image.
def get_image(self, hash_key):
my_image = self.image_engine.get_image(hash_key)
if my_image.get('is_viewed') == 0:
real_key = my_image.get('real_key')
root_path = os.path.join(self.image_path, real_key)
# call a function to set the image as "viewed"
return send_from_directory(root_path, '{}.png'.format(real_key))
else:
return render_template('404.html')
Doing it like this means you can add expiration to the hash key, or even a flag that says it was already viewed and then render nothing, or a 404 if they try to load it again.
This method does require a lot more database calls, but if you are out to protect your images, you will have to look at some performance options.

Related

Getting data from python flask to html through Javascript

I am learning data science but I am still new to flask, html and Js.
I have developed a ML model for home price prediction and would love to deploy it to Heroku.
The problem is the drop down menu in my frontend is not updated by the locations I have passed in my python flask backend.
here are the important parts of my code.
server.py:
from flask import Flask, request, jsonify, render_template
app = Flask(__name__)
#app.route('/locations')
def locations():
response = jsonify({
'locations': get_location_names()
})
response.headers.add('Access-Control-Allow-Origin', '*')
return response
app.js
function onPageLoad() {
console.log( "document loaded" );
$.get("{{ url_for('locations') }}",
function(data, status) {
console.log("got response for locations request");
if(data) {
var locations = data.locations;
var uiLocations = document.getElementById("uiLocations");
$('#uiLocations').empty();
for(var i in locations) {
var opt = new Option(locations[i]);
$('#uiLocations').append(opt);
}
}
});
index.html:
<!DOCTYPE html>
<html>
<head>
<title>Banglore Home Price Prediction</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"
type="text/javascript"></script>
<link rel="stylesheet" type= "text/css" href="{{url_for('static', filename = 'app.css')}}">
<script type="text/javascript" src ="{{url_for('static', filename = 'app.js')}}"></script>
</head>
the browser consoles prints "document loaded" which I placed in app.js but doesn't get the data from server.py.
I believe the issue is with the url_for statement but don't know how to go about it.
You can't use jinja2 expressions in a js file which is loaded as a static asset. - v25
You can add your Javascript in a <script> tag in the index.html file. Or you can hard code it.
I usually do not use either approachs. Instead, I render all the files with a custom python script before running the main app. I use a .bat file and type all the commands needed. You sometimes use Sass or any other thing that requires rendering... So it's helpful to be organized and write such a script. Use this approach if your JavaScript data doesn't change dynamically.
But if your script is dynamic, you can add a route that renders your file every time it is requested.
#app.route('/my_script.js')
def script():
return render_template('my_script.js', name='mark')
And in your /locations route:
<script src="{{url_for('script')}}"></script>
Jinja2 can parse any file regardless of it's type.

Run python script with flask from web without clicking any button

In my application, I need to open web cam inside webpage and also I need to process web cam frame and return result to webpage again. To do that I am not using buttons. I found that how to use webcam in webpage in here
web cam in a webpage using flask and python
However I cannot pass the result to the webpage. How can I pass the result to the same webpage ? Without clicking any button. In my case how can I call, index2() function from web ?
Python
from flask import Flask, render_template, Response, jsonify
from camera import VideoCamera
import cv2
app = Flask(__name__)
video_stream = VideoCamera()
#app.route('/')
def index():
return render_template('index.html')
def gen(camera):
while True:
frame = camera.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
#app.route('/video_feed')
def video_feed():
return Response(gen(video_stream),
mimetype='multipart/x-mixed-replace; boundary=frame')
#app.route('/print2')
def index2():
print2 = video_stream.get_print()
print("zzzz",print2)
return render_template('gui.html', printTo=print2)
if __name__ == '__main__':
app.run(host='127.0.0.1', debug=True,port="5000")
Python camera.py
class VideoCamera(object):
def __init__(self):
self.video = cv2.VideoCapture(0)
def __del__(self):
self.video.release()
def get_frame(self):
ret, frame = self.video.read()
# DO WHAT YOU WANT WITH TENSORFLOW / KERAS AND OPENCV
ret, jpeg = cv2.imencode('.jpg', frame)
return jpeg.tobytes()
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<title>Video Stream</title>
</head>
<body>
<img src="{{ url_for('video_feed') }}" />
</body>
</html>
In camera.py script I can process frame and I can print the results to log however I need to pass these results to the webpage.
I did many thing and none of them worked for me !
Please help me.
Thank you.
EDIT
As the comments states, as far as I understand I can do it with AJAX and I added this script but now script gives error
<script type="text/javascript" >
function plot() {
$.ajax({
url: '/print2',
success: function(data) {
console.log('get info');
$('#description').html(data['description']);
}
});
}
plot()
</script>
It says
(index):30 Uncaught ReferenceError: $ is not defined
at plot ((index):30)
at (index):38
Where is the problem ?
Have you included a reference to jQuery?
(index):30 Uncaught ReferenceError: $ is not defined at plot ((index):30) at (index):38

Display the contents of a text file within iframe in a html page rendered via flask web server

This is probably a simple question but I got somehow confused.
I'm using flask webserver to keep my UI up. This server generates a log file. I want to have, let's say, an iframe below the html page (the one which is rendered via flask render_template('index.html') ) showing the contents of that file.
I'm aware of the questions like this and thanks to #davidism I've learnt nice concepts about serving the static files but that's not exactly what I want to achieve.
So far I can say, again thanks to #davidism, that I have a main.py file like this:
from time import sleep
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/stream')
def stream():
def generate():
with open('job.log') as f:
while True:
yield f.read()
sleep(1)
return app.response_class(generate(), mimetype='text/plain')
app.run()
and by using this:
<pre id="output"></pre>
<script>
var output = document.getElementById('output');
var xhr = new XMLHttpRequest();
xhr.open('GET', '{{ url_for('stream') }}');
xhr.send();
setInterval(function() {
output.textContent = xhr.responseText;
}, 1000);
</script>
I get that log in a clean full page. How can I get this in that aforementioned way.
p.s: I have multiple html files which will be rendered in the future and I want to implement this in a way to have that iframe view of the log file in all pages.
An iframe is literally just another page contained within an element on your page. So your main page would just do:
<iframe src ="/stream"></iframe>
and that's it.

Display the contents of a log file as it is updated

I have external programs such as ffmpeg and gstreamer running in the background and writing to a log file. I want to display the contents of this log with my Flask application, so that the user can watch the log update, like tail -f job.log would do in the terminal.
I tried to use <object data="/out.log" type="text/plain"> to point at the log file, but that failed to show the data, or the browser told me I needed a plugin.
How can I embed and update the log file in an HTML page?
Use a Flask view to continuously read from the file forever and stream the response. Use JavaScript to read from the stream and update the page. This example sends the entire file, you may want to truncate that at some point to save bandwidth and memory. This example sleeps between reads to reduce cpu load from the endless loop and allow other threads more active time.
from time import sleep
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/stream')
def stream():
def generate():
with open('job.log') as f:
while True:
yield f.read()
sleep(1)
return app.response_class(generate(), mimetype='text/plain')
app.run()
<pre id="output"></pre>
<script>
var output = document.getElementById('output');
var xhr = new XMLHttpRequest();
xhr.open('GET', '{{ url_for('stream') }}');
xhr.send();
setInterval(function() {
output.textContent = xhr.responseText;
}, 1000);
</script>
This is almost the same as this answer, which describes how to stream and parse messages, although reading from an external file forever was novel enough to be it's own answer. The code here is simpler because we don't care about parsing messages or ending the stream, just tailing the file forever.
I am using frontail package from npm.
npm i frontail -g
frontail /var/log/syslog
visit http://127.0.0.1:9001 to view logs
Source: https://github.com/mthenw/frontail
This may not be the exact answer for the question(to embed an html page), but it solves the problem of many users who are looking specifically only for
Display the contents of a log file as it is updated
For me #davidism solution (accepted answer) worked only on Firefox. It didnt work in Chrome, Brave, Vivaldi. Maybe there was some kind of de-sync in backend and frontend loops? I dont know.
Anyway i used far simpler solution, without loop on the backend and javascript loop on frontend. Maybe it's "uglier" and may cause trouble for some very long logs, but at least it works on every browser i use.
#app.route('/stream')
def stream():
with open("job.log", "r") as f:
content = f.read()
# as you see, file is loaded only once, no loop here, (loop is on frontend side)
return app.response_class(content, mimetype='text/plain')
<!DOCTYPE html>
<html>
<head>
<!-- page auto-refresh every 10 seconds -->
<meta http-equiv="refresh" content="10">
<title>Some title</title>
</head>
<body>
<h1>Log file ...</h1>
<script>
// function for adjusting iframe height to log size
function resizeIframe(obj) {
obj.style.height = obj.contentWindow.document.documentElement.scrollHeight + 'px';
}
</script>
<!-- iframe pulls whole file -->
<iframe src="{{ url_for('stream') }}" frameborder="0" style="overflow:hidden;width:100%" width="100%" frameborder="0" scrolling="no" onload="resizeIframe(this)"></iframe>
</body>
</html>
As you see the only javascript code is used to adjust iframe height to current text size.

XHR responseText is empty string

Html Page:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>xhr</title>
</head>
<body>
<script>
var xhr_test = new XMLHttpRequest();
xhr_test.open("GET","xhrtest",true);
xhr_test.send();
alert(xhr_test.responseText);
</script>
</body>
</html>
The main.py file:
import webapp2
from handlers import cookies,pages
application = webapp2.WSGIApplication([
('/xhr',pages.XHR),
('/xhrtest', cookies.XHRTest)
],
debug=True)
The Request handlers:
class XHRTest(webapp2.RequestHandler):
def get(self):
self.response.write('0')
and,
class XHR(webapp2.RequestHandler):
def get(self):
f = open('static/html/xhr.html','r')
self.response.write(f.read())
Now, when I hit upon the url localhost:8080/xhrtest the browser promptly shows the response 0 as the page's content.
Hitting the url localhost:8080/xhr which indirectly hits /xhrtest, pops up an empty string in the alert box (the responseText is an empty string) but checking chrome's response tab under the network tab, I can see that the request's response is 0.
So why is xhr_test.responseText not able to display the same response?
The call to send is asynchronous (you've set the 'async' parameter to true), which means that your alert is happening immediately, before the request finishes.
You should add an event-listener to xhr.onreadystatechange and use the response within that.
Changing the 'true' to 'false' would make this simple example work, but is not a good idea in the general case.
The MDN page on Ajax explains how XMLHttpRequest should be used.

Categories