Remove everything related to encryption (#3396)

* remove requirements

* deprecate encrypt

* remove flagging

* deprecate

* formatting

* lint
This commit is contained in:
Abubakar Abid 2023-03-06 15:06:23 -08:00 committed by GitHub
parent 608d3b6250
commit 22c9254a12
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 36 additions and 202 deletions

View File

@ -1,7 +1,6 @@
from __future__ import annotations
import copy
import getpass
import inspect
import json
import os
@ -21,16 +20,7 @@ import requests
from anyio import CapacityLimiter
from typing_extensions import Literal
from gradio import (
components,
encryptor,
external,
networking,
queueing,
routes,
strings,
utils,
)
from gradio import components, external, networking, queueing, routes, strings, utils
from gradio.context import Context
from gradio.deprecation import check_deprecated_parameters
from gradio.documentation import document, set_documentation_group
@ -1278,7 +1268,7 @@ class Blocks(BlockContext):
show_tips: bool = False,
height: int = 500,
width: int | str = "100%",
encrypt: bool = False,
encrypt: bool | None = None,
favicon_path: str | None = None,
ssl_keyfile: str | None = None,
ssl_certfile: str | None = None,
@ -1308,7 +1298,7 @@ class Blocks(BlockContext):
max_threads: the maximum number of total threads that the Gradio app can generate in parallel. The default is inherited from the starlette library (currently 40). Applies whether the queue is enabled or not. But if queuing is enabled, this parameter is increaseed to be at least the concurrency_count of the queue.
width: The width in pixels of the iframe element containing the interface (used if inline=True)
height: The height in pixels of the iframe element containing the interface (used if inline=True)
encrypt: If True, flagged data will be encrypted by key provided by creator at launch
encrypt: DEPRECATED. Has no effect.
favicon_path: If a path to a file (.png, .gif, or .ico) is provided, it will be used as the favicon for the web page.
ssl_keyfile: If a path to a file is provided, will use this as the private key file to create a local server running on https.
ssl_certfile: If a path to a file is provided, will use this as the signed certificate for https. Needs to be provided if ssl_keyfile is provided.
@ -1350,6 +1340,11 @@ class Blocks(BlockContext):
"The `enable_queue` parameter has been deprecated. Please use the `.queue()` method instead.",
DeprecationWarning,
)
if encrypt is not None:
warnings.warn(
"The `encrypt` parameter has been deprecated and has no effect.",
DeprecationWarning,
)
if self.is_space:
self.enable_queue = self.enable_queue is not False
@ -1381,14 +1376,9 @@ class Blocks(BlockContext):
raise ValueError("In order to use batching, the queue must be enabled.")
self.config = self.get_config_file()
self.encrypt = encrypt
self.max_threads = max(
self._queue.max_thread_count if self.enable_queue else 0, max_threads
)
if self.encrypt:
self.encryption_key = encryptor.get_key(
getpass.getpass("Enter key for encryption: ")
)
if self.is_running:
assert isinstance(
@ -1430,9 +1420,6 @@ class Blocks(BlockContext):
# Workaround by triggering the app endpoint
requests.get(f"{self.local_url}startup-events")
if self.enable_queue:
if self.encrypt:
raise ValueError("Cannot queue with encryption enabled.")
utils.launch_counter()
if share is None:

View File

@ -2457,10 +2457,8 @@ class File(
"is_file": True,
}
def serialize(
self, x: str | None, load_dir: str = "", encryption_key: bytes | None = None
) -> Dict | None:
serialized = FileSerializable.serialize(self, x, load_dir, encryption_key)
def serialize(self, x: str | None, load_dir: str = "") -> Dict | None:
serialized = FileSerializable.serialize(self, x, load_dir)
if serialized is None:
return None
serialized["size"] = Path(serialized["name"]).stat().st_size
@ -3157,10 +3155,8 @@ class UploadButton(
def generate_sample(self):
return deepcopy(media_data.BASE64_FILE)
def serialize(
self, x: str | None, load_dir: str = "", encryption_key: bytes | None = None
) -> Dict | None:
serialized = FileSerializable.serialize(self, x, load_dir, encryption_key)
def serialize(self, x: str | None, load_dir: str = "") -> Dict | None:
serialized = FileSerializable.serialize(self, x, load_dir)
if serialized is None:
return None
serialized["size"] = Path(serialized["name"]).stat().st_size
@ -3884,7 +3880,6 @@ class Gallery(IOComponent, TempFileManager, FileSerializable):
self,
x: Any,
save_dir: str = "",
encryption_key: bytes | None = None,
root_url: str | None = None,
) -> None | str:
if x is None:

View File

@ -21,7 +21,7 @@ DEPRECATION_MESSAGE = {
"capture_session": simple_deprecated_notice("capture_session"),
"api_mode": simple_deprecated_notice("api_mode"),
"show_tips": use_in_launch("show_tips"),
"encrypt": use_in_launch("encrypt"),
"encrypt": simple_deprecated_notice("encrypt"),
"enable_queue": use_in_launch("enable_queue"),
"server_name": use_in_launch("server_name"),
"server_port": use_in_launch("server_port"),

View File

@ -1,31 +0,0 @@
from Crypto import Random
from Crypto.Cipher import AES
from Crypto.Hash import SHA256
def get_key(password: str) -> bytes:
"""Generates an encryption key based on the password provided."""
key = SHA256.new(password.encode()).digest()
return key
def encrypt(key: bytes, source: bytes) -> bytes:
"""Encrypts source data using the provided encryption key"""
IV = Random.new().read(AES.block_size) # generate IV
encryptor = AES.new(key, AES.MODE_CBC, IV)
padding = AES.block_size - len(source) % AES.block_size # calculate needed padding
source += bytes([padding]) * padding # Python 2.x: source += chr(padding) * padding
data = IV + encryptor.encrypt(source) # store the IV at the beginning and encrypt
return data
def decrypt(key: bytes, source: bytes) -> bytes:
IV = source[: AES.block_size] # extract the IV from the beginning
decryptor = AES.new(key, AES.MODE_CBC, IV)
data = decryptor.decrypt(source[AES.block_size :]) # decrypt
padding = data[-1] # pick the padding value from the end; Python 2.x: ord(data[-1])
if (
data[-padding:] != bytes([padding]) * padding
): # Python 2.x: chr(padding) * padding
raise ValueError("Invalid padding...")
return data[:-padding] # remove the padding

View File

@ -2,7 +2,6 @@ from __future__ import annotations
import csv
import datetime
import io
import json
import os
import time
@ -15,7 +14,7 @@ from typing import TYPE_CHECKING, Any, List
import pkg_resources
import gradio as gr
from gradio import encryptor, utils
from gradio import utils
from gradio.documentation import document, set_documentation_group
if TYPE_CHECKING:
@ -91,7 +90,6 @@ class FlaggingCallback(ABC):
self,
flag_data: List[Any],
flag_option: str = "",
flag_index: int | None = None,
username: str | None = None,
) -> int:
"""
@ -101,7 +99,6 @@ class FlaggingCallback(ABC):
interface: The Interface object that is being used to launch the flagging interface.
flag_data: The data to be flagged.
flag_option (optional): In the case that flagging_options are provided, the flag option that is being used.
flag_index (optional): The index of the sample that is being flagged.
username (optional): The username of the user that is flagging the data, if logged in.
Returns:
(int) The total number of samples that have been flagged.
@ -135,7 +132,6 @@ class SimpleCSVLogger(FlaggingCallback):
self,
flag_data: List[Any],
flag_option: str = "",
flag_index: int | None = None,
username: str | None = None,
) -> int:
flagging_dir = self.flagging_dir
@ -184,18 +180,15 @@ class CSVLogger(FlaggingCallback):
self,
components: List[IOComponent],
flagging_dir: str | Path,
encryption_key: bytes | None = None,
):
self.components = components
self.flagging_dir = flagging_dir
self.encryption_key = encryption_key
os.makedirs(flagging_dir, exist_ok=True)
def flag(
self,
flag_data: List[Any],
flag_option: str = "",
flag_index: int | None = None,
username: str | None = None,
) -> int:
flagging_dir = self.flagging_dir
@ -219,11 +212,7 @@ class CSVLogger(FlaggingCallback):
csv_data.append(str(sample))
else:
csv_data.append(
component.deserialize(
sample,
save_dir=save_dir,
encryption_key=self.encryption_key,
)
component.deserialize(sample, save_dir=save_dir)
if sample is not None
else ""
)
@ -231,53 +220,12 @@ class CSVLogger(FlaggingCallback):
csv_data.append(username if username is not None else "")
csv_data.append(str(datetime.datetime.now()))
def replace_flag_at_index(file_content: str, flag_index: int):
file_content_ = io.StringIO(file_content)
content = list(csv.reader(file_content_))
header = content[0]
flag_col_index = header.index("flag")
content[flag_index][flag_col_index] = flag_option
output = io.StringIO()
writer = csv.writer(output)
writer.writerows(utils.sanitize_list_for_csv(content))
return output.getvalue()
with open(log_filepath, "a", newline="", encoding="utf-8") as csvfile:
writer = csv.writer(csvfile)
if is_new:
writer.writerow(utils.sanitize_list_for_csv(headers))
writer.writerow(utils.sanitize_list_for_csv(csv_data))
if self.encryption_key:
output = io.StringIO()
if not is_new:
with open(log_filepath, "rb", encoding="utf-8") as csvfile:
encrypted_csv = csvfile.read()
decrypted_csv = encryptor.decrypt(
self.encryption_key, encrypted_csv
)
file_content = decrypted_csv.decode()
if flag_index is not None:
file_content = replace_flag_at_index(file_content, flag_index)
output.write(file_content)
writer = csv.writer(output)
if flag_index is None:
if is_new:
writer.writerow(utils.sanitize_list_for_csv(headers))
writer.writerow(utils.sanitize_list_for_csv(csv_data))
with open(log_filepath, "wb", encoding="utf-8") as csvfile:
csvfile.write(
encryptor.encrypt(self.encryption_key, output.getvalue().encode())
)
else:
if flag_index is None:
with open(log_filepath, "a", newline="", encoding="utf-8") as csvfile:
writer = csv.writer(csvfile)
if is_new:
writer.writerow(utils.sanitize_list_for_csv(headers))
writer.writerow(utils.sanitize_list_for_csv(csv_data))
else:
with open(log_filepath, encoding="utf-8") as csvfile:
file_content = csvfile.read()
file_content = replace_flag_at_index(file_content, flag_index)
with open(
log_filepath, "w", newline="", encoding="utf-8"
) as csvfile: # newline parameter needed for Windows
csvfile.write(file_content)
with open(log_filepath, "r", encoding="utf-8") as csvfile:
line_count = len([None for row in csv.reader(csvfile)]) - 1
return line_count
@ -368,7 +316,6 @@ class HuggingFaceDatasetSaver(FlaggingCallback):
self,
flag_data: List[Any],
flag_option: str = "",
flag_index: int | None = None,
username: str | None = None,
) -> int:
self.repo.git_pull(lfs=True)
@ -500,7 +447,6 @@ class HuggingFaceDatasetJSONSaver(FlaggingCallback):
self,
flag_data: List[Any],
flag_option: str = "",
flag_index: int | None = None,
username: str | None = None,
) -> str:
self.repo.git_pull(lfs=True)

View File

@ -22,7 +22,7 @@ from fastapi import UploadFile
from ffmpy import FFmpeg, FFprobe, FFRuntimeError
from PIL import Image, ImageOps, PngImagePlugin
from gradio import encryptor, utils
from gradio import utils
with warnings.catch_warnings():
warnings.simplefilter("ignore") # Ignore pydub warning if ffmpeg is not installed
@ -62,11 +62,12 @@ def decode_base64_to_image(encoding: str) -> Image.Image:
return img
def encode_url_or_file_to_base64(path: str | Path, encryption_key: bytes | None = None):
if utils.validate_url(str(path)):
return encode_url_to_base64(str(path), encryption_key=encryption_key)
def encode_url_or_file_to_base64(path: str | Path):
path = str(path)
if utils.validate_url(path):
return encode_url_to_base64(path)
else:
return encode_file_to_base64(str(path), encryption_key=encryption_key)
return encode_file_to_base64(path)
def get_mimetype(filename: str) -> str | None:
@ -89,11 +90,9 @@ def get_extension(encoding: str) -> str | None:
return extension
def encode_file_to_base64(f, encryption_key=None):
def encode_file_to_base64(f):
with open(f, "rb") as file:
encoded_string = base64.b64encode(file.read())
if encryption_key:
encoded_string = encryptor.decrypt(encryption_key, encoded_string)
base64_str = str(encoded_string, "utf-8")
mimetype = get_mimetype(f)
return (
@ -104,10 +103,8 @@ def encode_file_to_base64(f, encryption_key=None):
)
def encode_url_to_base64(url, encryption_key=None):
def encode_url_to_base64(url):
encoded_string = base64.b64encode(requests.get(url).content)
if encryption_key:
encoded_string = encryptor.decrypt(encryption_key, encoded_string)
base64_str = str(encoded_string, "utf-8")
mimetype = get_mimetype(url)
return (
@ -274,9 +271,7 @@ def decode_base64_to_binary(encoding) -> Tuple[bytes, str | None]:
return base64.b64decode(data), extension
def decode_base64_to_file(
encoding, encryption_key=None, file_path=None, dir=None, prefix=None
):
def decode_base64_to_file(encoding, file_path=None, dir=None, prefix=None):
if dir is not None:
os.makedirs(dir, exist_ok=True)
data, extension = decode_base64_to_binary(encoding)
@ -299,8 +294,6 @@ def decode_base64_to_file(
suffix="." + extension,
dir=dir,
)
if encryption_key is not None:
data = encryptor.encrypt(encryption_key, data)
file_obj.write(data)
file_obj.flush()
return file_obj

View File

@ -10,9 +10,7 @@ from gradio.context import Context
class Serializable(ABC):
@abstractmethod
def serialize(
self, x: Any, load_dir: str | Path = "", encryption_key: bytes | None = None
):
def serialize(self, x: Any, load_dir: str | Path = ""):
"""
Convert data from human-readable format to serialized format for a browser.
"""
@ -23,7 +21,6 @@ class Serializable(ABC):
self,
x: Any,
save_dir: str | Path | None = None,
encryption_key: bytes | None = None,
root_url: str | None = None,
):
"""
@ -33,15 +30,12 @@ class Serializable(ABC):
class SimpleSerializable(Serializable):
def serialize(
self, x: Any, load_dir: str | Path = "", encryption_key: bytes | None = None
) -> Any:
def serialize(self, x: Any, load_dir: str | Path = "") -> Any:
"""
Convert data from human-readable format to serialized format. For SimpleSerializable components, this is a no-op.
Parameters:
x: Input data to serialize
load_dir: Ignored
encryption_key: Ignored
"""
return x
@ -49,7 +43,6 @@ class SimpleSerializable(Serializable):
self,
x: Any,
save_dir: str | Path | None = None,
encryption_key: bytes | None = None,
root_url: str | None = None,
):
"""
@ -57,7 +50,6 @@ class SimpleSerializable(Serializable):
Parameters:
x: Input data to deserialize
save_dir: Ignored
encryption_key: Ignored
root_url: Ignored
"""
return x
@ -68,7 +60,6 @@ class ImgSerializable(Serializable):
self,
x: str | None,
load_dir: str | Path = "",
encryption_key: bytes | None = None,
) -> str | None:
"""
Convert from human-friendly version of a file (string filepath) to a seralized
@ -76,21 +67,17 @@ class ImgSerializable(Serializable):
Parameters:
x: String path to file to serialize
load_dir: Path to directory containing x
encryption_key: Used to encrypt the file
"""
if x is None or x == "":
return None
is_url = utils.validate_url(x)
path = x if is_url else Path(load_dir) / x
return processing_utils.encode_url_or_file_to_base64(
path, encryption_key=encryption_key
)
return processing_utils.encode_url_or_file_to_base64(path)
def deserialize(
self,
x: str | None,
save_dir: str | Path | None = None,
encryption_key: bytes | None = None,
root_url: str | None = None,
) -> str | None:
"""
@ -99,14 +86,11 @@ class ImgSerializable(Serializable):
Parameters:
x: Base64 representation of image to deserialize into a string filepath
save_dir: Path to directory to save the deserialized image to
encryption_key: Used to decrypt the file
root_url: Ignored
"""
if x is None or x == "":
return None
file = processing_utils.decode_base64_to_file(
x, dir=save_dir, encryption_key=encryption_key
)
file = processing_utils.decode_base64_to_file(x, dir=save_dir)
return file.name
@ -115,7 +99,6 @@ class FileSerializable(Serializable):
self,
x: str | None,
load_dir: str | Path = "",
encryption_key: bytes | None = None,
) -> Dict | None:
"""
Convert from human-friendly version of a file (string filepath) to a
@ -123,16 +106,13 @@ class FileSerializable(Serializable):
Parameters:
x: String path to file to serialize
load_dir: Path to directory containing x
encryption_key: Used to encrypt the file
"""
if x is None or x == "":
return None
filename = str(Path(load_dir) / x)
return {
"name": filename,
"data": processing_utils.encode_url_or_file_to_base64(
filename, encryption_key=encryption_key
),
"data": processing_utils.encode_url_or_file_to_base64(filename),
"orig_name": Path(filename).name,
"is_file": False,
}
@ -141,7 +121,6 @@ class FileSerializable(Serializable):
self,
x: str | Dict | None,
save_dir: Path | str | None = None,
encryption_key: bytes | None = None,
root_url: str | None = None,
) -> str | None:
"""
@ -150,7 +129,6 @@ class FileSerializable(Serializable):
Parameters:
x: Base64 representation of file to deserialize into a string filepath
save_dir: Path to directory to save the deserialized file to
encryption_key: Used to decrypt the file
root_url: If this component is loaded from an external Space, this is the URL of the Space
"""
if x is None:
@ -158,9 +136,7 @@ class FileSerializable(Serializable):
if isinstance(save_dir, Path):
save_dir = str(save_dir)
if isinstance(x, str):
file_name = processing_utils.decode_base64_to_file(
x, dir=save_dir, encryption_key=encryption_key
).name
file_name = processing_utils.decode_base64_to_file(x, dir=save_dir).name
elif isinstance(x, dict):
if x.get("is_file", False):
if root_url is not None:
@ -175,7 +151,7 @@ class FileSerializable(Serializable):
).name
else:
file_name = processing_utils.decode_base64_to_file(
x["data"], dir=save_dir, encryption_key=encryption_key
x["data"], dir=save_dir
).name
else:
raise ValueError(
@ -189,7 +165,6 @@ class JSONSerializable(Serializable):
self,
x: str | None,
load_dir: str | Path = "",
encryption_key: bytes | None = None,
) -> Dict | None:
"""
Convert from a a human-friendly version (string path to json file) to a
@ -197,7 +172,6 @@ class JSONSerializable(Serializable):
Parameters:
x: String path to json file to read to get json string
load_dir: Path to directory containing x
encryption_key: Ignored
"""
if x is None or x == "":
return None
@ -207,7 +181,6 @@ class JSONSerializable(Serializable):
self,
x: str | Dict,
save_dir: str | Path | None = None,
encryption_key: bytes | None = None,
root_url: str | None = None,
) -> str | None:
"""
@ -216,7 +189,6 @@ class JSONSerializable(Serializable):
Parameters:
x: Json string
save_dir: Path to save the deserialized json file to
encryption_key: Ignored
root_url: Ignored
"""
if x is None:

View File

@ -10,7 +10,6 @@ numpy
orjson
pandas
pillow
pycryptodome
python-multipart
pydub
pyyaml

View File

@ -1,27 +0,0 @@
import os
from gradio import encryptor, processing_utils
from gradio.media_data import BASE64_IMAGE
os.environ["GRADIO_ANALYTICS_ENABLED"] = "False"
class TestKeyGenerator:
def test_same_pass(self):
key1 = encryptor.get_key("test")
key2 = encryptor.get_key("test")
assert key1 == key2
def test_diff_pass(self):
key1 = encryptor.get_key("test")
key2 = encryptor.get_key("diff_test")
assert key1 != key2
class TestEncryptorDecryptor:
def test_same_pass(self):
key = encryptor.get_key("test")
data, _ = processing_utils.decode_base64_to_binary(BASE64_IMAGE)
encrypted_data = encryptor.encrypt(key, data)
decrypted_data = encryptor.decrypt(key, encrypted_data)
assert data == decrypted_data