コード例 #1
0
def run_api_with_authentication_required():
    """Runs the api with authentication requirement.
    Errors: :class:`ActionNeedsAuthenticationToken`, :class:`InvalidAuthenticationToken`.
    """
    if "authentication_token" not in request.form:
        raise ActionNeedsAuthenticationToken()
    if not check_token(hash_key(request.form["authentication_token"])):
        raise InvalidAuthenticationToken()
コード例 #2
0
def delete_file(key: str, filename: str):
    """Deletes a file (not authenticated)
    :param key: The key of the file.
    :param filename: The filename of the file.
    :return:
    """
    key_path = get_data_directory() + hash_key(key)
    remove(key_path + "/" + filename)
    remove(key_path + "/" + private_key_file_name)
    rmdir(key_path)
コード例 #3
0
def parse_authentication(key: str, filename: str):
    """Parses the authentication (private_key) from a request.
    Errors: :class:`FileDoesNotExists`, :class:`AccessDenied`.
    :param key: The key of the target file.
    :param filename: The filename of the file.
    :return
    """
    if "private_key" not in request.form:
        raise BadRequest()
    authenticate(hash_key(key), filename, request.form["private_key"])
コード例 #4
0
def authenticate_group(group_name: str, private_key: str):
    """Authenticates group with private_key.
    :param group_name: The name of the group.
    :param private_key: The private_key of the group
    """
    if not exists(get_group_directory() + "/" + group_name):
        raise GroupDoesNotExists()
    with open(
            get_group_directory() + "/" + group_name + "/" +
            private_key_file_name, "r") as file:
        if not file.read().replace("\n", "") == hash_key(private_key):
            raise AccessDenied()
コード例 #5
0
def create_authentication_token(key_identifier: str) -> str:
    """Creates new encrypted authentication token.
    :param key_identifier: The identifier of the key (The key variable key name on the server configuration).
    :return:
    """
    if key_identifier not in config.KEYS:
        raise AuthenticationKeyNotFound()
    key = RSA.import_key(
        base64.b64decode(config.KEYS[key_identifier].encode("utf-8")))
    token = generate_random_key(config.RANDOM_AUTHENTICATION_TOKEN_LENGTH)
    authentication_tokens.append(hash_key(token))
    encrypted_token = base64.b64encode(
        PKCS1_OAEP.new(key).encrypt(token.encode("utf-8"))).decode("utf-8")
    return encrypted_token
コード例 #6
0
def authenticate(key: str, filename: str, private_key: str):
    """Authenticates with the private_key.
    :param key: The key of the target file.
    :param filename: The filename of the file.
    :param private_key: The private_key of the file.
    """
    if not exists(get_data_directory() + key + "/" + filename):
        raise FileDoesNotExists()
    if not exists(get_data_directory() + key + "/" + private_key_file_name):
        raise AccessDenied()
    with open(get_data_directory() + key + "/" +
              private_key_file_name) as file:
        if hash_key(private_key) != file.read():
            raise AccessDenied()
コード例 #7
0
def handle_request_path(path):
    """Handles the request path. If the path contains a key (encrypting key),
    the key will be replaced with the hash of the key.
    :param path: The raw path of request: string.
    :return: The new path (string).
    """
    regex = rf"\/[\w{config.ALLOWED_FILENAME_CHARACTERS}]+"
    matches = re.finditer(regex, path, re.MULTILINE)
    match_list: List[re.Match] = []
    for match in matches:
        match_list.append(match)
    if len(match_list) == 2 and "." in match_list[1].group():
        # This is a key request and the key would be censored (hashed)
        key = hash_key(match_list[0].group()[1:])
        return f"/{key}{match_list[1].group()}"
    return path
コード例 #8
0
ファイル: groups.py プロジェクト: AdriDevelopsThings/OpenCDN
def download_group_file(name: str, key: str, filename: str):
    """Download a group file. Attention: Do not share a group file link, because every file in the group is encrypted
    with the same key. With this file and all filenames the client can download every file from the group. With the
    link nobody can look or delete a group.
    :param name: The name of the group.
    :param key: The encrypting key of the group.
    :param filename: The name of the file.

    Download: (GET)
    ===========

    Errors: :class:`FileDoesNotExists`.
    Returns: error or the raw content of the file.

    Delete: (DELETE)
    ===========

    Requires: private_key (the private_key of the group).
    Errors: :class:`FileDoesNotExists`, :class:`AccessDenied`.
    Returns: error or success json.
    """
    if not is_group_name_valid(name):
        raise FileDoesNotExists()
    if ".." in filename or "/" in filename:
        raise FileDoesNotExists()
    hashed_key = hash_key(key)
    path = f"{get_group_directory()}/{name}/{hashed_key}"
    if not exists(path):
        raise FileDoesNotExists()
    file_path = f"{path}/{filename}"
    if not exists(file_path):
        raise FileDoesNotExists()
    if request.method == "GET":
        with open(file_path, "rb") as file:
            content = file.read()
        decrypted_content = decrypt(content, key)
        file = BytesIO()
        file.write(decrypted_content)
        file.seek(0)
        return send_file(file, attachment_filename=filename)
    elif request.method == "DELETE":
        if "private_key" not in request.form:
            raise BadRequest()
        private_key = request.form["private_key"]
        authenticate_group(name, private_key)
        remove(file_path)
        return jsonify({"status": "success"})
コード例 #9
0
def download(key: str, filename: str):
    """The flask download method for downloading and deleting.
    Downloading: (GET)
    ============
    Requires: /<key>/<filename>
            key: The decrypting key and identifier for the file.
            filename: The name of the file.
    Errors: :class:`FileDoesNotExists`.
    Return: error or the file.

    Deleting: (DELETE)
    ============
    Requires: /<key>/<filename>
            key: The decrypting key and identifier for the file.
            filename: The name of the file.
            And the private_key of the file.
    Errors: :class:`FileDoesNotExists`, :class:`AccessDenied`.
    Return: error or success json.
    """
    if "/" in key or "/" in filename or ".." in key or ".." in filename:
        raise FileDoesNotExists()
    hashed_key = hash_key(key)
    filepath = f"{config.DATA_DIRECTORY}{hashed_key}/{filename}"
    if not exists(filepath):
        raise FileDoesNotExists()
    if request.method == "GET":
        with open(filepath, "rb") as file:
            content = file.read()
        decrypted_content = decrypt(content, key)
        file = BytesIO()
        file.write(decrypted_content)
        file.seek(0)
        return send_file(file, attachment_filename=filename)
    elif request.method == "DELETE":
        parse_authentication(key, filename)
        delete_file(key, filename)
        return jsonify({"status": "success"})
コード例 #10
0
ファイル: upload.py プロジェクト: AdriDevelopsThings/OpenCDN
def upload_method():
    """The flask upload method for uploading.
    Requires: a 'file' file which contains the file to uploaded.
    Optional: If authentication is enabled, you must set the authentication form values.
              You can set 'private_key' to your private_key. If 'private_key' is not set,
              the server would generate a random private_key.
              Group Uploading:
              If you would like to update a file in a group you must hand over the 'group', 'private_key' and the 'key'
              of the group. The 'group' parameter is the group name. If you use group uploading following errors
              can be thrown: :class:`GroupDoesNotExists`, :class:`AccessDenied`.
    Errors: :class:`ActionNeedsAuthenticationToken`, :class:`InvalidAuthenticationToken`, :class:`NoFileInRequest`,
            :class:`InvalidFileName`, :class:`InvalidFileSuffix`, :class:`InvalidFileName`, :class:`FileTooBig`.
    Return: errors or json {
                'key': 'the_encrypting_key (string).',
                'hashed_key': 'the encrypting_key hashed (string).',
                'filename': 'the name of the file (string).',
                'private_key': 'the private_key of the file (string).',
            ]
    """
    if config.AUTHENTICATION_FOR_UPLOADING_REQUIRED:
        run_api_with_authentication_required()
    if "file" not in request.files:
        raise NoFileInRequest()
    file = request.files["file"]
    if file.filename == "" or "/" in file.filename or "\\" in file.filename: # PTA protection
        raise InvalidFileName()
    if not is_file_suffix_valid(file.filename):
        raise InvalidFileSuffix()
    if not is_filename_valid(file.filename):
        raise InvalidFileName()
    group = None
    key = None
    if "group" in request.form:
        if "key" not in request.form or "private_key" not in request.form:
            raise BadRequest()
        group = request.form["group"]
        key = request.form["key"]
        if not is_group_name_valid(group):
            raise GroupDoesNotExists()
        authenticate_group(group, request.form["private_key"])
    filename = secure_filename(file.filename)
    if key is None:
        key = generate_random_key(config.RANDOM_KEY_LENGTH) # The encrypting key
    if "private_key" in request.form:
        private_key = request.form["private_key"]
    else:
        private_key = generate_random_key(config.RANDOM_PRIVATE_KEY_LENGTH)
    hashed_key = hash_key(key)
    hashed_private_key = hash_key(private_key)
    content = file.read()
    if len(content) > config.MAX_FILE_BYTES:
        raise FileTooBig()
    if group is None:
        out_directory = get_data_directory() + hashed_key
        mkdir(out_directory)
        with open(out_directory + "/" + filename, "wb") as file:
            file.write(encrypt(content, key))
        with open(out_directory + "/" + private_key_file_name, "w") as file:
            file.write(hashed_private_key)
        logger.log(
            LogType.INFO,
            f"New upload from {get_real_ip()} to {hashed_key}/{filename} with filesize {len(content)}.",
        )
        return jsonify(
            {
                "key": key,
                "hashed_key": hashed_key,
                "filename": filename,
                "private_key": private_key,
            }
        )
    else:
        files_directory = f"{get_group_directory()}/{group}/{hashed_key}"
        if not exists(files_directory):
            raise GroupDoesNotExists()
        if exists(files_directory + "/" + filename):
            raise FileAlreadyExists()
        with open(files_directory + "/" + filename, "wb") as file:
            file.write(encrypt(content, key))

        logger.log(
            LogType.INFO,
            f"New upload from {get_real_ip()} to (group) {group}/{hashed_key}/{filename} with filesize {len(content)}.",
        )
        return jsonify(
            {
                "key": key,
                "hashed_key": hashed_key,
                "filename": filename,
                "private_key": private_key,
                "group": group
            }
        )
コード例 #11
0
ファイル: groups.py プロジェクト: AdriDevelopsThings/OpenCDN
def group(name: str):
    """Show, Create and Delete groups.
    :param name: The name of the group.

    Show Group: (PUT)
    ==========
    Requires: private_key (the private_key of the group), key (the key of the group).
    Errors: :class:`GroupDoesNotExists`, :class:`ActionDenied`.
    Returns: error or json {
                'hashed_key': 'the key, but hashed.',
                'files': 'List of filenames, which are saved in this group.',
            }

    Create Group: (POST)
    ==========
    Optional: private_key: The private_key of the group (if the private_key is not set,
        the server will generate it itself), If authentication is enabled, you must set the authentication form values.
    Errors: :class:`ActionNeedsAuthenticationToken`, :class:`InvalidAuthenticationToken`, :class:`InvalidGroupName`,
        :class:`GroupAlreadyExists`
    Return: error or json {
                'name': 'The name of the group.',
                'key': 'The key of the group.',
                'hashed_key': 'The key of the group, but hashed',
                'private_key': 'The private key of the group.'
            }

    Delete Group: (DELETE)
    Requires: private_key (the private_key of the group).
    Errors: :class:`GroupDoesNotExists`, :class:`ActionDenied`.
    Returns: error or success json.
    ==========


    """
    if request.method == "PUT":
        if not is_group_name_valid(name):
            raise GroupDoesNotExists()
        path = get_group_directory() + f"/{name}"
        if not exists(path):
            raise GroupDoesNotExists()
        if "private_key" not in request.form or "key" not in request.form:
            raise BadRequest()
        key = request.form["key"]
        hashed_key = hash_key(key)
        private_key = request.form["private_key"]
        authenticate_group(name, private_key)
        if not exists(path + "/" + hashed_key):
            raise GroupDoesNotExists()
        informations = {
            "hashed_key": hashed_key,
            "files": listdir(path + "/" + hashed_key),
        }
        return jsonify(informations)
    elif request.method == "POST":
        if config.AUTHENTICATION_FOR_UPLOADING_REQUIRED:
            run_api_with_authentication_required()
        if not is_group_name_valid(name):
            raise InvalidGroupName()
        path = get_group_directory() + f"/{name}"
        if exists(path):
            raise GroupAlreadyExists()
        if "private_key" in request.form:
            private_key = request.form["private_key"]
        else:
            private_key = generate_random_key(config.RANDOM_PRIVATE_KEY_LENGTH)
        key = generate_random_key(config.RANDOM_KEY_LENGTH)
        hashed_key = hash_key(key)
        mkdir(path)
        mkdir(path + "/" + hashed_key)
        with open(path + "/private.key", "w") as private_file:
            private_file.write(hash_key(private_key))
        return jsonify(
            {
                "name": name,
                "key": key,
                "hashed_key": hashed_key,
                "private_key": private_key,
            }
        )
    elif request.method == "DELETE":
        if "private_key" not in request.form:
            raise BadRequest()
        private_key = request.form["private_key"]
        authenticate_group(name, private_key)
        path = get_group_directory() + f"/{name}"
        shutil.rmtree(path)
        return jsonify({"status": "success"})
コード例 #12
0
def delete_authentication_token(token: str):
    """Deletes an authentication token
    :param token: The authentication token to be deleted.
    """
    authentication_tokens.remove(hash_key(token))