def daemon(): global status while True: try: status = 'disconnected' dev = getDevice() printer.info('USB Connected') status = 'connected' dev.reset() dev.set_configuration() cfg = dev.get_active_configuration() def is_out_ep(ep): return usb.util.endpoint_direction(ep.bEndpointAddress) == \ usb.util.ENDPOINT_OUT def is_in_ep(ep): return usb.util.endpoint_direction(ep.bEndpointAddress) == \ usb.util.ENDPOINT_IN out_ep = usb.util.find_descriptor(cfg[(0, 0)], custom_match=is_out_ep) in_ep = usb.util.find_descriptor(cfg[(0, 0)], custom_match=is_in_ep) assert out_ep is not None assert in_ep is not None poll_commands(in_ep, out_ep) except BaseException as e: printer.error('usb exception: ' + str(e)) time.sleep(1)
def load(path='conf/users.conf'): global users if not os.path.isfile(path): id = 'guest' users[id] = User() users[id].setPassword('guest') users[id].setId('guest') return firstLine = True map = ['id', 'password'] with open(path, encoding="utf-8-sig") as f: for line in f.readlines(): if firstLine: firstLine = False continue line = line.strip() if len(line) == 0 or line[0] == '#': continue if re.match(r'[A-Za-z\|\s]+', line, re.I): map = line.split('|') t = User() t.setPassword(map[1]) t.setId(map[0]) users[t.id] = t printer.info('loaded user ' + str(t.id))
def load(fileName='conf/files.json'): global hasLoaded if hasLoaded: return hasLoaded = True try: timestamp = time.process_time() if os.path.isfile(fileName): with open(fileName, encoding="utf-8-sig") as f: for k in json.loads(f.read()): t = Nsp(None, None) t.path = k['path'] t.titleId = k['titleId'] t.version = k['version'] if 'fileSize' in k: t.fileSize = k['fileSize'] if not t.path: continue path = os.path.abspath(t.path) if os.path.isfile(path) and os.path.exists( path) and not __is_file_hidden(path): files[path] = t # Fs.Nsp(path, None) except: raise printer.info(f'loaded file list in {time.process_time() - timestamp} ' + 'seconds')
def initFiles(): global isInitFiles if isInitFiles: return isInitFiles = True printer.info('Loading NSPs from the configuration file') nsps.load()
def send(self, timeout=60000): printer.info('sending %d bytes' % len(self.payload)) self.o.write(b'\x12\x12\x12\x12', timeout=timeout) self.o.write(struct.pack('<I', self.command), timeout=timeout) self.o.write(struct.pack('<Q', len(self.payload)), timeout=timeout) # size self.o.write(struct.pack('<I', 0), timeout=timeout) # threadId self.o.write(struct.pack('<H', 0), timeout=timeout) # packetIndex self.o.write(struct.pack('<H', 0), timeout=timeout) # packetCount self.o.write(struct.pack('<Q', 0), timeout=timeout) # timestamp self.o.write(self.payload, timeout=timeout)
def _write(self, data): printer.info('usbresponse write') if self.bytesSent == 0 and not self.headersSent: self.sendHeader() if type(data) == str: data = data.encode('utf-8') if not len(data): return self.bytesSent += len(data) self.packet.payload = data self.packet.send(10 * 60 * 1000)
def scan(): global hasScanned hasScanned = True initFiles() r = 0 printer.info('Scanning NSPs on the filesystem') for path in config.paths.scan: r += nsps.scan(path) printer.info('Saving NSPs to the configuration file') nsps.save() return r
def setPath(self, path): self.path = path self.version = '0' z = re.search(r'.*\[([a-fA-F0-9]{16})\].*', path, re.I) if z: self.titleId = z.groups()[0].upper() else: printer.info('could not get title id from filename, name needs ' + 'to contain [titleId] : ' + path) self.titleId = None z = re.match(r'.*\[v([0-9]+)\].*', path, re.I) if z: self.version = z.groups()[0]
def route(request, response, verb='get'): try: if len(request.bits) > 0 and request.bits[0] in mappings: i = request.bits[1] methodName = verb + i[0].capitalize() + i[1:] printer.info('routing to ' + methodName) method = getattr( mappings[request.bits[0]], methodName, Response404, ) method(request, response, **request.query) return True except BaseException as e: printer.error('route exception: ' + str(e)) return None return False
def removeEmptyDir(path, removeRoot=True): if not os.path.isdir(path): return # remove empty subfolders _files = os.listdir(path) if len(_files): for f in _files: if not f.startswith('.') and not f.startswith('_'): fullpath = os.path.join(path, f) if os.path.isdir(fullpath): removeEmptyDir(fullpath) # if folder empty, delete it _files = os.listdir(path) if len(_files) == 0 and removeRoot: printer.info("Removing empty folder:" + path) os.rmdir(path)
def __init__(self, url): self.headers = {} self.path = url self.head = False self.url = urlparse(self.path) printer.info('url ' + self.path) self.bits = [x for x in self.url.path.split('/') if x] self.query = parse_qs(self.url.query) try: for k, v in self.query.items(): self.query[k] = v[0] except: pass self.user = None
def scan(base, force=False): global hasScanned hasScanned = True i = 0 fileList = {} printer.info(base) for root, _, _files in os.walk(base, topdown=False, followlinks=True): for name in _files: if __is_file_hidden(name): continue suffix = pathlib.Path(name).suffix if suffix in ['.nsp', '.nsz', '.nsz', '.xci', '.xcz']: path = os.path.abspath(root + '/' + name) fileList[path] = name if len(fileList) == 0: save() return 0 progress = status.create(len(fileList), desc='Scanning files...') try: for path, name in fileList.items(): try: progress.add(1) if path not in files: printer.info('scanning ' + name) nsp = Nsp(path, None) nsp.getFileSize() files[nsp.path] = nsp i = i + 1 if i % 20 == 0: save() except KeyboardInterrupt: progress.close() raise except BaseException as e: printer.info('An error occurred processing file: ' + str(e)) raise save() progress.close() except BaseException as e: printer.info('An error occurred scanning files: ' + str(e)) raise return i
def run(): global httpd global sock global addr printer.info( f'{time.asctime()} Server Starts - {config.server.hostname}:' + f'{config.server.port}') try: addr = (config.server.hostname, config.server.port) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.bind(addr) sock.listen(5) [Thread(i) for i in range(16)] for thread in threads: thread.join() except KeyboardInterrupt: pass printer.info(f'{time.asctime()} Server Stops - {config.server.hostname}:' + f'{config.server.port}')
def recv(self, timeout=60000): printer.info('begin recv') header = bytes(self.i.read(32, timeout=timeout)) printer.info('read complete') magic = header[:4] self.command = int.from_bytes(header[4:8], byteorder='little') self.size = int.from_bytes(header[8:16], byteorder='little') self.threadId = int.from_bytes(header[16:20], byteorder='little') self.packetIndex = int.from_bytes(header[20:22], byteorder='little') self.packetCount = int.from_bytes(header[22:24], byteorder='little') self.timestamp = int.from_bytes(header[24:32], byteorder='little') if magic != b'\x12\x12\x12\x12': printer.error('invalid magic! ' + str(magic)) return False printer.info('receiving %d bytes' % self.size) self.payload = bytes(self.i.read(self.size, timeout=0)) return True
args = parser.parse_args() if args.silent: printer.silent = True if args.hostname: args.server = True config.server.hostname = args.hostname if args.port: args.server = True config.server.port = int(args.port) status.start() printer.info(' ,;:;;,') printer.info(' ;;;;;') printer.info(' .=\', ;:;;:,') printer.info(' /_\', "=. \';:;:;') printer.info(' @=:__, \\,;:;:\'') printer.info(' _(\\.= ;:;;\'') printer.info(' `"_( _/="`') printer.info(' `"\'') if args.usb: try: from nut_impl import usb except BaseException as e: printer.error('pip3 install pyusb, required for USB coms: ' + f'{str(e)}') nut_impl.scan()
def serveFile(response, path, filename=None, start=None, end=None): try: if start is not None: start = int(start) if end is not None: end = int(end) if not filename: filename = os.path.basename(path) response.attachFile(filename) chunkSize = 0x400000 with open(path, "rb") as f: f.seek(0, 2) size = f.tell() if start and end: if end is None: end = size - 1 else: end = int(end) if start is None: start = size - end else: start = int(start) if start >= size or start < 0 or end <= 0: return server.Response400( None, response, 'Invalid range request %d - %d' % (start, end)) response.setStatus(206) else: if start is None: start = 0 if end is None: end = size if end >= size: end = size if end <= start: response.write(b'') return printer.info('ranged request for %d - %d' % (start, end)) f.seek(start, 0) response.setMime(path) response.setHeader('Accept-Ranges', 'bytes') response.setHeader('Content-Range', f'bytes {start}-{end-1}/{size}') response.setHeader('Content-Length', str(end - start)) response.sendHeader() if not response.head: size = end - start i = 0 progress = status.create( size, 'Downloading ' + os.path.basename(path)) while i < size: chunk = f.read(min(size - i, chunkSize)) i += len(chunk) progress.add(len(chunk)) if chunk: pass response.write(chunk) else: break progress.close() except BaseException as e: printer.error('File download exception: ' + str(e)) traceback.print_exc(file=sys.stdout) if response.bytesSent == 0: response.write(b'')
def getDownload(request, response, start=None, end=None): try: nsp = nsps.getByTitleId(request.bits[2]) response.attachFile(nsp.titleId + '.nsp') if len(request.bits) >= 5: start = int(request.bits[-2]) end = int(request.bits[-1]) chunkSize = 0x400000 with open(nsp.path, "rb") as f: f.seek(0, 2) size = f.tell() if 'Range' in request.headers: _range = request.headers.get('Range').strip() start, end = _range.strip('bytes=').split('-') if end == '': end = size - 1 else: end = int(end) + 1 if start == '': start = size - end else: start = int(start) if start >= size or start < 0 or end <= 0: return server.Response400( request, response, f'Invalid range request {start} - {end}') response.setStatus(206) else: if start is None: start = 0 if end is None: end = size if end >= size: end = size if end <= start: response.write(b'') return printer.info('ranged request for %d - %d' % (start, end)) f.seek(start, 0) response.setMime(nsp.path) response.setHeader('Accept-Ranges', 'bytes') response.setHeader('Content-Range', f'bytes {start}-{end-1}/{size}') response.setHeader('Content-Length', str(end - start)) response.sendHeader() if not response.head: size = end - start i = 0 progress = status.create( size, 'Downloading ' + os.path.basename(nsp.path)) while i < size: chunk = f.read(min(size - i, chunkSize)) i += len(chunk) progress.add(len(chunk)) if chunk: pass response.write(chunk) else: break progress.close() except BaseException as e: printer.error('NSP download exception: ' + str(e)) traceback.print_exc(file=sys.stdout) if response.bytesSent == 0: response.write(b'')