I am currently designing a steganography web app as a part of my beginner Computer Science summer program. With a very limited understanding of HTML, Flask, and the interconnected languages like SQL and jquery, I've ran into a bit of a roadblock. So far I've looked at a lot of beginner's flask tutorials, but they all have a tendency to focus on creating forums with users and the ability to post.
My vision for the web app is to have a page titled "encrypt" that has two fields required (text/message and an image to put the text in) and a submit button that then runs my python program and gives the user the image with the hidden message. Through a ton of web searches, I've found ways to make a form with two fields and how to upload to a folder.
Somewhere in the middle, however, my web app began to strongly resemble Frankenstein's monster with bits of code taken from every which place stitched into one disfigured and possibly (read probably) incoherent code. Of course, as a result of this, my code fails to do the very thing it was made to do.
My steganography code works well enough (shown to give a better understanding of what I aim to achieve. The larger goal of this is more applicable because it aims to use multiple user-submitted values in order to run a python program and does not involve registered members, a desire that most tutorials neglect):
def packing(s):
'''converts a characters 8 bits into 4 two-bit values and adds them to a
list using a for loop'''
l = []
for i in range(len(s)):
x = ord(s[i])
top2 = (x & 0xC0) >> 6
middletop2 = (x & 0x30) >> 4
lowertop2 = (x & 0xC) >> 2
lower2 = (x & 0x3)
l.extend([top2, middletop2, lowertop2, lower2])
length = len(l)
h1 = (length & 0xC0000000) >> 30
h2 = (length & 0x30000000) >> 28
h3 = (length & 0x0C000000) >> 26
h4 = (length & 0x03000000) >> 24
h5 = (length & 0x00C00000) >> 22
h6 = (length & 0x00300000) >> 20
h7 = (length & 0x000C0000) >> 18
h8 = (length & 0x00030000) >> 16
h9 = (length & 0x0000C000) >> 14
hA = (length & 0x00003000) >> 12
hB = (length & 0x00000C00) >> 10
hC = (length & 0x00000300) >> 8
hD = (length & 0x000000C0) >> 6
hE = (length & 0x00000030) >> 4
hF = (length & 0x0000000C) >> 2
hF1 = (length & 0x00000003)
l = ([h1] + [h2] + [h3] + [h4] + [h5] + [h6] + [h7] + [h8] + [h9] +
[hA] + [hB] + [hC] + [hD] + [hE] + [hF] + [hF1] + l)
return l
def bitsIntoImage(pic, l):
'''wipes the last two bits of each R, G and B value for every pixel
nevessary to import the message. Then writes the rest of the image onto the
new image to return a complete image.'''
pic = Image.open( pic )
draw = ImageDraw.Draw(pic)
(width, height) = pic.size
newPic = Image.new('RGB', (width,height))
drawnewPic = ImageDraw.Draw(newPic)
if len(l) % 3 == 1:
l = l + [0,0]
if len(l) % 3 == 2:
l = l + [0]
redL = l[0::3]
greenL = l[1::3]
blueL = l[2::3]
for y in xrange(height):
for x in xrange(width):
if len(redL) > 0:
openRed = pic.getpixel((x,y))[0] &~ 0x3
openGreen = pic.getpixel((x,y))[1] &~ 0x3
openBlue = pic.getpixel((x,y))[2] &~ 0x3
codedRed = openRed | redL[0]
codedGreen = openGreen | greenL[0]
codedBlue = openBlue | blueL[0]
redL = redL[1:]
greenL = greenL[1:]
blueL = blueL[1:]
drawnewPic.point([x,y], (codedRed, codedGreen, codedBlue))
else:
(R, G, B) = pic.getpixel((x,y))
drawnewPic.point([x,y], (R, G, B))
return newPic
def step1(pic, s):
'''pic = picture, s = message/string. Turns the string into a list of
double-bit information, then imports that string of information into the image'''
l = packing(s)
picture = bitsIntoImage(pic, l)
return picture
But I'm pretty sure that my actual code fails to hold the user submitted image and message in such a way that my steganography program can actually use the values:
import os
import tempfile
import re
from flask.ext.wtf import Form
from wtforms import StringField, TextAreaField, FileField, validators
from wtforms.validators import DataRequired
from flask_wtf.file import FileAllowed, FileRequired
from werkzeug import secure_filename
from PIL import Image, ImageDraw
from steganography import packing, bitsIntoImage, step1, MinaB, unpacking, step2
UPLOAD_FOLDER = '/Users/AustinMossEnnis/practice/uploads/'
ALLOWED_EXTENSIONS = set(['png'])
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS
app = Flask(__name__)
app.config['SECRET_KEY'] = 'string'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
class EncryptForm(Form):
image = FileField(u'Upload your image:', validators = ['png'])
message = TextAreaField(u'Enter your message:', [validators.Length(min=1)])
def validate_image(form, field):
if field.data:
field.data = re.sub(r'[^a-z0-9_.-]', '_', field.data)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/encrypt', methods=['GET', 'POST'])
def encrypt():
form = EncryptForm(request.form)
if request.method == "POST" and 'docs' in request.files:
#I had tried using "if form.image.data and form.validate():" to no avail
image_data = request.FILES[form.image.name].read()
step1(image_data, form.message())
file.save(os.path.join(app.config['UPLOAD_FOLDER'], newPic))
redirect(url_for('uploaded_file',
newPic=filename))
return render_template('encrypt.html',
title='Encrpyt',
form=form)
@app.route('/encrypt/<filename>')
def encrypted_file(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'],
filename)
if __name__ == '__main__':
app.run(
host="0.0.0.0",
port=int("5000"),
debug=True
)
As you can tell from my residual imports, I've tried a ton of things with mixed results. Along the way, I've gotten "error, v # invalid expression", "TypeError: 'str' object is not callable", amongst other error messages.
So, in summary, my question is how I can properly take the values submitted by the user, integrate them into my program, and then give back the product of that program?
Would it be preferable to have a temp folder of some sort? Is it necessary to create databases regardless of whether or not I have users? I've tried a lot but have failed either due to a failure to properly execute the text or as a result of not understanding the code I was trying to execute.