import time import hashlib import bencode import resumablehashlib from app import app ANNOUNCE_URL = app.config.get('TORRENT_ANNOUNCE_URL') NAMING_SALT = app.config.get('TORRENT_NAMING_SALT') REGISTRY_TITLE = app.config.get('REGISTRY_TITLE') def public_torrent_filename(blob_uuid): return hashlib.sha256(blob_uuid).hexdigest() def per_user_torrent_filename(user_uuid, blob_uuid): return hashlib.sha256(blob_uuid + user_uuid + NAMING_SALT).hexdigest() def make_torrent(name, webseed, length, piece_length, pieces): return bencode.bencode({ 'announce': ANNOUNCE_URL, 'url-list': webseed, 'encoding': 'UTF-8', 'created by': REGISTRY_TITLE, 'creation date': int(time.time()), 'info': { 'name': name, 'length': length, 'piece length': piece_length, 'pieces': pieces, }, }) class PieceHasher(object): def __init__(self, piece_size, starting_offset, starting_piece_hash_bytes, hash_fragment_to_resume): if not isinstance(starting_offset, (int, long)): raise TypeError('starting_offset must be an integer') elif not isinstance(piece_size, (int, long)): raise TypeError('piece_size must be an integer') self._current_offset = starting_offset self._piece_size = piece_size self._hash_fragment = hash_fragment_to_resume self._piece_hashes = bytearray(starting_piece_hash_bytes) def update(self, buf): buf_offset = 0 while buf_offset < len(buf): buf_bytes_to_hash = buf[0:self._piece_length_remaining()] to_hash_len = len(buf_bytes_to_hash) if self._piece_offset() == 0 and to_hash_len > 0 and self._current_offset > 0: # We are opening a new piece self._piece_hashes.extend(self._hash_fragment.digest()) self._hash_fragment = resumablehashlib.sha1() self._hash_fragment.update(buf_bytes_to_hash) self._current_offset += to_hash_len buf_offset += to_hash_len def _piece_length_remaining(self): return self._piece_size - (self._current_offset % self._piece_size) def _piece_offset(self): return self._current_offset % self._piece_size @property def piece_hashes(self): return self._piece_hashes @property def hash_fragment(self): return self._hash_fragment