You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

67 lines
1.9 KiB

  1. import csv
  2. import re
  3. import shlex
  4. import sys
  5. csv.field_size_limit(2 ** 31 - 1)
  6. dict_params = re.compile(r":([^\ \,\.\\\(\)\=]+)")
  7. list_params = re.compile(r"\?")
  8. class AndroidSQLConn:
  9. def __init__(self, device, filepath, use_root=True):
  10. self.device = device
  11. self.filepath = filepath
  12. self.root = use_root
  13. def _quote_param_(param):
  14. if isinstance(param, str):
  15. return "'{}'".format(param.replace("'", "''"))
  16. elif isinstance(param, bool):
  17. return "1" if param else "0"
  18. elif param is None:
  19. return "NULL"
  20. else:
  21. return str(param)
  22. def _sub_params_(SQL, params):
  23. params = iter(params)
  24. try:
  25. return list_params.sub(
  26. lambda match: AndroidSQLConn._quote_param_(next(params)), SQL
  27. )
  28. except StopIteration:
  29. raise TypeError("Not enough parameters")
  30. def _sub_params_dict_(SQL, params):
  31. try:
  32. return dict_params.sub(
  33. lambda match: AndroidSQLConn._quote_param_(params[match.group(1)]), SQL
  34. )
  35. except KeyError:
  36. raise TypeError("Parameter specified but not in mapping")
  37. def execute(self, SQL, params=None):
  38. if params:
  39. if isinstance(params, dict):
  40. SQL = AndroidSQLConn._sub_params_dict_(SQL, params)
  41. else:
  42. SQL = AndroidSQLConn._sub_params_(SQL, params)
  43. SQL = shlex.quote(SQL)
  44. if self.root:
  45. shell = self.device.sudo
  46. else:
  47. shell = self.device.shell
  48. out = shell(
  49. "sqlite3", "-header", "-csv", shlex.quote(self.filepath), SQL, output="out"
  50. )
  51. if out:
  52. return csv.DictReader(out.splitlines())
  53. if __name__ == "__main__":
  54. print(
  55. AndroidSQLConn._sub_params_(
  56. "SELECT * FROM table WHERE name=?,age=?;", ["boby;DROP TABLE table", 1]
  57. )
  58. )