From 57c2ba5ccc75de2f7cf01ba6949de7a4f4a98948 Mon Sep 17 00:00:00 2001 From: ThaaoBlues Date: Sat, 2 Jul 2022 19:23:50 +0200 Subject: [PATCH 1/9] first try of isbn auto lookup --- client.py | 1 - copypasta.py | 2 +- requirements.txt | 1 + templates/index.html | 4 ++-- test.py | 38 ++++++++++++++++++++++++++++++++------ util.py | 30 +++++++++++++++++++++++++++++- 6 files changed, 65 insertions(+), 11 deletions(-) diff --git a/client.py b/client.py index 7fd6ced..d6e5888 100644 --- a/client.py +++ b/client.py @@ -1,5 +1,4 @@ import requests -from ast import literal_eval from util import * def send_text_scan(text): diff --git a/copypasta.py b/copypasta.py index 329003d..e62cf4a 100644 --- a/copypasta.py +++ b/copypasta.py @@ -566,7 +566,7 @@ def upload(): isbn = r - store_to_history({"file_type" : "isbn", "content" : f"{isbn}", "date" :f"{time}"}) + store_to_history({"file_type" : "isbn", "content" : f"{isbn}", "date" :f"{time}","isbn_lookup":identify_product(isbn)}) return jsonify({"upload_status" : "true"}) diff --git a/requirements.txt b/requirements.txt index d82069e..afb1c79 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,3 +6,4 @@ pyautogui pillow waitress webtest +beautifulsoup4 diff --git a/templates/index.html b/templates/index.html index 77484d1..00fb044 100644 --- a/templates/index.html +++ b/templates/index.html @@ -246,9 +246,9 @@

Last files/data sent :

//barcode type }else if(obj.file_type == "isbn"){ - search_icon = ""; + search_icon = ""; - tab_element = "
isbn:"+obj.content+"
"+search_icon+copy_content_icon+delete_scan_icon+"
"; + tab_element = "
isbn: "+obj.content+" | name: "+obj.isbn_lookup.name+"
"+search_icon+copy_content_icon+delete_scan_icon+"
"; //emails }else if(obj.file_type == "email"){ diff --git a/test.py b/test.py index 510efd6..3f17947 100644 --- a/test.py +++ b/test.py @@ -1,9 +1,35 @@ -from ast import literal_eval -from os import startfile from requests import get +from json import loads +from bs4 import BeautifulSoup +#isbn = "3302740068027" +#isbn = "978209157545" +isbn = "3270220060949" -startfile("C:/") - - -print(literal_eval(get("https://api.github.com/repos/CopyPastaOfficial/CopyPasta/tags").text)[0]['name']) \ No newline at end of file +def identify_product(isbn:str): + + + + # edible product ? + r = get(f"http://world.openfoodfacts.org/api/v0/product/{isbn}") + r = loads(r.text) + if "product" in r.keys(): + r = r["product"] + + return {"name":r["product_name"]+ " - "+r["brands"] if "brands" in r.keys() else r["product_name"] ,"url":f"https://world.openfoodfacts.org/product/{isbn}"} + + + # book ? + r = get(f"https://www.isbnsearcher.com/books/{isbn}",headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36 Edg/103.0.1264.37"}) + + if r.status_code == 200: + r = BeautifulSoup(r.text,"html.parser") + + return {"name":r.find("h1").get_text(),"url":f"https://www.isbnsearcher.com/books/{isbn}"} + + else: + return {"name":isbn,"url":f"https://www.google.com/search?q={isbn}"} + +#print(identify_product(isbn)) +# amazon lookup +r = get("https://www.amazon.fr/s?k=9782091575452",headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36 Edg/103.0.1264.37"},allow_redirects=True) diff --git a/util.py b/util.py index fba836a..44b3063 100644 --- a/util.py +++ b/util.py @@ -2,6 +2,7 @@ from getpass import getuser from random import randint from json import * +from bs4 import BeautifulSoup from requests import get from os import mkdir, path, remove from xml.etree import ElementTree @@ -327,4 +328,31 @@ def remove_copypasta_port_redirect(): def is_image(file_type:str): - return file_type in ["jpeg","jpg","png","ico","gif","apng","avif","gif","jfif","pjpeg","pjp","svg","webp"] \ No newline at end of file + return file_type in ["jpeg","jpg","png","ico","gif","apng","avif","gif","jfif","pjpeg","pjp","svg","webp"] + + + +def identify_product(isbn:str): + + + + # edible product ? + r = get(f"http://world.openfoodfacts.org/api/v0/product/{isbn}") + r = loads(r.text) + + if "product" in r.keys(): + r = r["product"] + + return {"name":r["product_name"]+ " - "+r["brands"] if "brands" in r.keys() else r["product_name"] ,"url":f"https://world.openfoodfacts.org/product/{isbn}"} + + + # book ? + r = get(f"https://www.isbnsearcher.com/books/{isbn}",headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.53 Safari/537.36 Edg/103.0.1264.37"}) + + if r.status_code == 200: + r = BeautifulSoup(r.text,"html.parser") + + return {"name":r.find("h1").get_text(),"url":f"https://www.isbnsearcher.com/books/{isbn}"} + + else: + return {"name":isbn,"url":f"https://www.google.com/search?q={isbn}"} \ No newline at end of file From c64db90ce109f0e082a65e68844e14b1e0bf727b Mon Sep 17 00:00:00 2001 From: ThaaoBlues Date: Sun, 3 Jul 2022 15:34:45 +0200 Subject: [PATCH 2/9] replaced path in url by id --- copypasta.py | 68 +++++++++++++++++++++++++++++++++++++------- templates/index.html | 8 +++--- 2 files changed, 62 insertions(+), 14 deletions(-) diff --git a/copypasta.py b/copypasta.py index e62cf4a..5294ec6 100644 --- a/copypasta.py +++ b/copypasta.py @@ -1,3 +1,4 @@ +from readline import get_current_history_length, get_history_length import sys import socket from flask import Flask, render_template, abort,jsonify,send_file,request,redirect,flash @@ -270,7 +271,7 @@ def process(process_id): try: image_id = request.args.get("image_id",type=int) - except: + except ValueError: return jsonify({"error":"wrong image_id argument type/no argument passed"}) image_path = get_history_file_by_id(image_id) @@ -378,31 +379,78 @@ def process(process_id): if process_id == "[OPEN FILE]": - Process(target=startfile,args=("{}/{}".format(APP_PATH,request.args.get("file_path")),)).start() + try: + file_id = request.args.get("file_id",type=int) + except ValueError: + return jsonify({"error":"invalid url argument"}) + + + json_dict = get_history_file_by_id(file_id) + + if not json_dict: # id does not exists + return jsonify({"error":"invalid url argument"}) + + Process(target=startfile,args=("{}/{}".format(APP_PATH,json_dict["path"]),)).start() return redirect("/") if process_id == "[COPY WIFI PW]": + + try: + scan_id = request.args.get("scan_id",type=int) + except ValueError: + return jsonify({"error":"invalid url argument"}) + + + json_dict = get_history_file_by_id(scan_id) + + if not json_dict: # id does not exists + return jsonify({"error":"invalid url argument"}) + + + if not "content" in json_dict.keys(): + return jsonify({"this kind of scan cannot be copied to clipboard"}) + - copy(get_history_file_by_id(int(request.args.get("scan_id")))['password']) + copy(json_dict['password']) return redirect("/") if process_id == "[COPY CONTENT]": - copy(get_history_file_by_id(int(request.args.get("scan_id")))['content']) - + try: + scan_id = request.args.get("scan_id",type=int) + except ValueError: + return jsonify({"error":"invalid url argument"}) + + + json_dict = get_history_file_by_id(scan_id) + + if not json_dict: # id does not exists + return jsonify({"error":"invalid url argument"}) + + + if not "content" in json_dict.keys(): + return jsonify({"this kind of scan cannot be copied to clipboard"}) + + # finally, if nothing is wrong, copy the scan content + copy(json_dict["content"]) + return redirect("/") if process_id == "[OPEN VIDEO]": - file_path = request.args.get('file_path') + try: + video_id = request.args.get('video_id',type=int) + except ValueError: + return jsonify({"error":"invalid url argument"}) - # try to secure the file path - # if suspicious path, just go home - if (not path.exists(file_path)) or (not file_path.startswith("static/files_hist/")) or (".." in file_path): - return redirect("/") + if video_id <= get_history_file_last_id(): + file_path = get_history_file_by_id(video_id)["path"] + + else: # id does not exists + return jsonify({"error":"invalid url argument"}) return render_template("video_preview.html",file_path=file_path) diff --git a/templates/index.html b/templates/index.html index 00fb044..d6ab444 100644 --- a/templates/index.html +++ b/templates/index.html @@ -215,14 +215,14 @@

Last files/data sent :

//videos }else if(videos_ext.includes(obj.file_type)){ - var open_file_icon = ""; + var open_file_icon = ""; - var play_video_icon = ""; + var play_video_icon = ""; tab_element = "
title:"+obj.file_name+"
"+play_video_icon+open_file_icon+"
"+open_folder_icon+delete_file_icon+"
"; //audio }else if(audios_ext.includes(obj.file_type)){ - var open_file_icon = ""; + var open_file_icon = ""; tab_element = "
title:"+obj.file_name+"
"+open_folder_icon+"
"+open_file_icon+delete_file_icon+"
"; @@ -266,7 +266,7 @@

Last files/data sent :

//random file }else{ - var open_file_icon = " "; + var open_file_icon = " "; tab_element = ""+obj.date+""+obj.file_name+""+open_folder_icon+"
"+open_file_icon+delete_file_icon+""; } From e7345356e86baaec5a2cad75fee4fa9eb44a4642 Mon Sep 17 00:00:00 2001 From: ThaaoBlues Date: Sun, 3 Jul 2022 15:42:37 +0200 Subject: [PATCH 3/9] a bit of code cleaning --- copypasta.py | 95 ++++++++++++++++++++++------------------------------ 1 file changed, 40 insertions(+), 55 deletions(-) diff --git a/copypasta.py b/copypasta.py index 5294ec6..f169913 100644 --- a/copypasta.py +++ b/copypasta.py @@ -122,8 +122,16 @@ def history(i): """ if request.remote_addr == "127.0.0.1": - - file_data = get_history_file_by_id(int(i)) + try: + i = int(i) + except ValueError: + return jsonify({"Error","Invalid url variable. Here, it must be an integer."}) + + + file_data = get_history_file_by_id(i) + + if not file_data: + return jsonify({"Error":"This scan id does not exists."}) #rewrite the scan temporary file with the old scan with open("static/scan.Blue","w") as f: @@ -144,14 +152,14 @@ def img_preview(): try: image_id = request.args.get("image_id",type=int) - except: - return jsonify({"error":"wrong image_id argument type/no argument passed"}) + except ValueError: + return jsonify({"Error":"wrong image_id argument type/no argument passed"}) image_path = get_history_file_by_id(image_id) if not image_path: - return jsonify({"error":"this id does not belongs to any file"}) + return jsonify({"Error":"this id does not belongs to any file"}) else: image_path = image_path["path"] @@ -196,14 +204,14 @@ def process(process_id): try: file_id = request.args.get("file_id",type=int) - except: - return jsonify({"error":"wrong file_id argument type/no argument passed"}) + except ValueError: + return jsonify({"Error":"wrong file_id argument type/no argument passed"}) file_path = get_history_file_by_id(file_id) if not file_path: - return jsonify({"error":"this id does not belongs to any file"}) + return jsonify({"Error":"this id does not belongs to any file"}) remove(file_path['path']) @@ -216,22 +224,8 @@ def process(process_id): try: image_id = request.args.get("image_id",type=int) - except: - return jsonify({"error":"wrong image_id argument type/no argument passed"}) - - image_path = get_history_file_by_id(image_id) - - if not image_path: - return jsonify({"error":"this id does not belongs to any file"}) - - else: - - image_path = image_path["path"] - - # try to secure the image path - # if suspicious path, just go home - if (not path.exists(image_path)) or (not image_path.startswith("static/files_hist/")) or (".." in image_path): - return redirect("/") + except ValueError: + return jsonify({"Error":"wrong image_id argument type/no argument passed"}) return redirect(f"/image_preview?image_id={image_id}") @@ -240,17 +234,15 @@ def process(process_id): try: scan_id = request.args.get("scan_id",type=int) - except: - return jsonify({"error":"wrong scan_id argument type/no argument passed"}) + except ValueError: + return jsonify({"Error":"wrong scan_id argument type/no argument passed"}) text = get_history_file_by_id(scan_id) if not text: - return jsonify({"error":"this id does not belongs to any sacn"}) + return jsonify({"Error":"this id does not belongs to any sacn"}) - text = text["text"] - - copy(text) + copy(text["text"]) return redirect("/") @@ -258,8 +250,8 @@ def process(process_id): try: scan_id = request.args.get("scan_id",type=int) - except: - return jsonify({"error":"wrong scan_id argument type/no argument passed"}) + except ValueError: + return jsonify({"Error":"wrong scan_id argument type/no argument passed"}) delete_history_file_by_id(scan_id) @@ -272,22 +264,15 @@ def process(process_id): try: image_id = request.args.get("image_id",type=int) except ValueError: - return jsonify({"error":"wrong image_id argument type/no argument passed"}) + return jsonify({"Error":"wrong image_id argument type/no argument passed"}) image_path = get_history_file_by_id(image_id) if not image_path: - return jsonify({"error":"this id does not belongs to any file"}) + return jsonify({"Error":"this id does not belongs to any file"}) - else: - - image_path = image_path["path"] - - # try to secure the image path - # if suspicious path, just go home - if (not path.exists(image_path)) or (not image_path.startswith("static/files_hist/")) or (".." in image_path): - return redirect("/") + image_path = image_path["path"] return send_file(image_path, download_name=secure_filename(image_path.replace("static/files_hist/","")), @@ -317,12 +302,12 @@ def process(process_id): try: image_id = request.args.get("image_id",type=int) except: - return jsonify({"error":"wrong image_id argument type/no argument passed"}) + return jsonify({"Error":"wrong image_id argument type/no argument passed"}) image_path = get_history_file_by_id(image_id) if not image_path: - return jsonify({"error":"this id does not belongs to any file"}) + return jsonify({"Error":"this id does not belongs to any file"}) else: @@ -382,13 +367,13 @@ def process(process_id): try: file_id = request.args.get("file_id",type=int) except ValueError: - return jsonify({"error":"invalid url argument"}) + return jsonify({"Error":"invalid url argument"}) json_dict = get_history_file_by_id(file_id) if not json_dict: # id does not exists - return jsonify({"error":"invalid url argument"}) + return jsonify({"Error":"invalid url argument"}) Process(target=startfile,args=("{}/{}".format(APP_PATH,json_dict["path"]),)).start() @@ -400,13 +385,13 @@ def process(process_id): try: scan_id = request.args.get("scan_id",type=int) except ValueError: - return jsonify({"error":"invalid url argument"}) + return jsonify({"Error":"invalid url argument"}) json_dict = get_history_file_by_id(scan_id) if not json_dict: # id does not exists - return jsonify({"error":"invalid url argument"}) + return jsonify({"Error":"invalid url argument"}) if not "content" in json_dict.keys(): @@ -423,13 +408,13 @@ def process(process_id): try: scan_id = request.args.get("scan_id",type=int) except ValueError: - return jsonify({"error":"invalid url argument"}) + return jsonify({"Error":"invalid url argument"}) json_dict = get_history_file_by_id(scan_id) if not json_dict: # id does not exists - return jsonify({"error":"invalid url argument"}) + return jsonify({"Error":"invalid url argument"}) if not "content" in json_dict.keys(): @@ -444,13 +429,13 @@ def process(process_id): try: video_id = request.args.get('video_id',type=int) except ValueError: - return jsonify({"error":"invalid url argument"}) + return jsonify({"Error":"invalid url argument"}) if video_id <= get_history_file_last_id(): file_path = get_history_file_by_id(video_id)["path"] else: # id does not exists - return jsonify({"error":"invalid url argument"}) + return jsonify({"Error":"invalid url argument"}) return render_template("video_preview.html",file_path=file_path) @@ -514,7 +499,7 @@ def api(api_req): return jsonify({"success":"shutting down CopyPasta server..."}) else: - return jsonify({"error" : "wrong api call"}) + return jsonify({"Error" : "wrong api call"}) else: @@ -550,7 +535,7 @@ def upload(): file_type = r['type'] r = r['content'] except: - return jsonify({"upload_status" : "false","error":"malformed json"}), 400 + return jsonify({"upload_status" : "false","Error":"malformed json"}), 400 if file_type == "text": @@ -657,7 +642,7 @@ def upload(): else: - return jsonify({"upload_status" : "false","error" : "unknown type"}), 400 + return jsonify({"upload_status" : "false","Error" : "unknown type"}), 400 #multipart request (files) From eef899eeb11d3901f9cf86b2684e66d8f1ac1424 Mon Sep 17 00:00:00 2001 From: ThaaoBlues Date: Sun, 3 Jul 2022 16:04:40 +0200 Subject: [PATCH 4/9] speeeed --- util.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/util.py b/util.py index 44b3063..216c7b7 100644 --- a/util.py +++ b/util.py @@ -177,14 +177,21 @@ def init_history_file(force=False): def get_history(): - history = "{\"history\" : [" + # using lists and join() to speed up + history = ["{\"history\" : ["] for element in ElementTree.parse("static/history.xml").getroot(): - history += element.text + "," + history.append(element.text) + history.append(",") + - history = history[:-1] + "]}" if history != "{\"history\" : [" else history +"]}" + if len(history) > 1: + history.pop() + history.append("]}") + else: + history +"]}" - return history + return "".join(history) def get_history_file_last_id(): return len(ElementTree.parse("static/history.xml").getroot()) -1 @@ -192,8 +199,6 @@ def get_history_file_last_id(): def get_history_file_by_id(file_id): - history = [] - if file_id < len(ElementTree.parse("static/history.xml").getroot()): return loads(ElementTree.parse("static/history.xml").getroot()[file_id].text) From 1a25674993ca505bb6bdd928eb85e318a71cdd54 Mon Sep 17 00:00:00 2001 From: ThaaoBlues Date: Mon, 4 Jul 2022 15:09:14 +0200 Subject: [PATCH 5/9] new features ! Send files and text to your phone ! --- copypasta.py | 46 ++++++++++++++++++++++++++++++++++++++------ templates/index.html | 37 ++++++++++++++++++++++++++++++++++- test.py | 39 ++++++------------------------------- 3 files changed, 82 insertions(+), 40 deletions(-) diff --git a/copypasta.py b/copypasta.py index f169913..5154409 100644 --- a/copypasta.py +++ b/copypasta.py @@ -1,12 +1,13 @@ -from readline import get_current_history_length, get_history_length import sys import socket -from flask import Flask, render_template, abort,jsonify,send_file,request,redirect,flash -from itsdangerous import json +from flask import Flask, render_template, abort,jsonify,send_file,request,redirect,flash, send_from_directory +from tkinter import Tk +from tkinter.filedialog import askopenfilename from requests import get from os import path,remove, startfile, rename,chdir import PIL.Image as Image from io import BytesIO +from shutil import copyfile try: import win32clipboard except ImportError: @@ -456,6 +457,7 @@ def api(api_req): if request.remote_addr == "127.0.0.1": + if api_req == "get_history": @@ -498,10 +500,30 @@ def api(api_req): return jsonify({"success":"shutting down CopyPasta server..."}) + elif api_req == "gen_otdl_url": + + # keep main window hidden + root = Tk() + root.attributes("-topmost", True) + root.withdraw() + # open file dialog + file_path = askopenfilename(parent=root) + + if not file_path: + return jsonify({"Error":"no file selected"}) + + + if not path.exists("static/ot_upload"): + mkdir("static/ot_upload") + + #move file in a downloadable directory + copyfile(file_path,path.join(APP_PATH,f"static/ot_upload/{path.basename(file_path)}")) + + # return url to javascript for qr code generation and notification + return f"http://{get_private_ip()}:21987/download?file={path.basename(file_path)}" else: return jsonify({"Error" : "wrong api call"}) - else: if api_req == "ping": @@ -512,9 +534,21 @@ def api(api_req): return abort(403) +@app.route("/download",methods=["GET"]) - - +def download(): + + try: + file = request.args.get("file",type=str) + except: + return jsonify({"Error":"Invalid url parameter"}) + + file_path = path.join(APP_PATH,"static","ot_upload",file) + if path.exists(file_path): + print("exists",file_path) + return send_file(file_path,as_attachment=True) + else: + return jsonify({"Error":"This file does not exists or have already been downloaded one time."}) @app.route("/upload",methods=["POST"]) diff --git a/templates/index.html b/templates/index.html index d6ab444..30d931b 100644 --- a/templates/index.html +++ b/templates/index.html @@ -24,7 +24,15 @@ - + + + + @@ -140,6 +148,33 @@

Last files/data sent :

+ + + + + + +
+ +
You can close this page once you have downloaded your file.
+
+ + + + + + + + + + \ No newline at end of file diff --git a/util.py b/util.py index 243e1ab..fcbad99 100644 --- a/util.py +++ b/util.py @@ -16,10 +16,11 @@ from win10toast_click import ToastNotifier from win32com.client import Dispatch from platform import system +from time import sleep -TEMPLATES_FILES = ["favicon.ico","index.html","scan_preview.html","img_preview.html","video_preview.html"] +TEMPLATES_FILES = ["favicon.ico","index.html","scan_preview.html","img_preview.html","video_preview.html","download_page.html"] def notify_desktop(title,text): @@ -362,3 +363,9 @@ def identify_product(isbn:str): else: return {"name":isbn,"url":f"https://www.google.com/search?q={isbn}"} + +def delete_ot_dl_proc(APP_PATH,file:str): + + sleep(30) + # delete file after download as it is only a one timer + remove(path.join(APP_PATH,"static","ot_upload",file)) \ No newline at end of file