btformats.py 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import re
  2. from BTL.translation import _
  3. from BTL import BTFailure
  4. allowed_path_re = re.compile(r'^[^/\\.~][^/\\]*$')
  5. ints = (long, int)
  6. def check_info(info, check_paths=True):
  7. if not isinstance(info, dict):
  8. raise BTFailure, _("bad metainfo - not a dictionary")
  9. pieces = info.get('pieces')
  10. if type(pieces) != str or len(pieces) % 20 != 0 or len(pieces) == 0:
  11. raise BTFailure, _("bad metainfo - bad pieces key")
  12. piecelength = info.get('piece length')
  13. if type(piecelength) not in ints or piecelength <= 0:
  14. raise BTFailure, _("bad metainfo - illegal piece length")
  15. name = info.get('name')
  16. if not isinstance(name, str):
  17. raise BTFailure, _("bad metainfo - bad name")
  18. #if not allowed_path_re.match(name):
  19. # raise BTFailure, _("name %s disallowed for security reasons") % name
  20. if info.has_key('files') == info.has_key('length'):
  21. raise BTFailure, _("single/multiple file mix")
  22. if info.has_key('length'):
  23. length = info.get('length')
  24. if type(length) not in ints or length < 0:
  25. raise BTFailure, _("bad metainfo - bad length")
  26. else:
  27. files = info.get('files')
  28. if type(files) != list:
  29. raise BTFailure, _('bad metainfo - "files" is not a list of files')
  30. for f in files:
  31. if type(f) != dict:
  32. raise BTFailure, _("bad metainfo - file entry must be a dict")
  33. length = f.get('length')
  34. if type(length) not in ints or length < 0:
  35. raise BTFailure, _("bad metainfo - bad length")
  36. path = f.get('path')
  37. if type(path) != list or path == []:
  38. raise BTFailure, _("bad metainfo - bad path")
  39. for p in path:
  40. if type(p) != str:
  41. raise BTFailure, _("bad metainfo - bad path dir")
  42. if check_paths and not allowed_path_re.match(p):
  43. raise BTFailure, _("path %s disallowed for security reasons") % p
  44. f = ['/'.join(x['path']) for x in files]
  45. f.sort()
  46. i = iter(f)
  47. try:
  48. name2 = i.next()
  49. while True:
  50. name1 = name2
  51. name2 = i.next()
  52. if name2.startswith(name1):
  53. if name1 == name2:
  54. raise BTFailure, _("bad metainfo - duplicate path")
  55. elif name2[len(name1)] == '/':
  56. raise BTFailure(_("bad metainfo - name used as both"
  57. "file and subdirectory name"))
  58. except StopIteration:
  59. pass
  60. def check_message(message, check_paths=True):
  61. if type(message) != dict:
  62. raise BTFailure, _("bad metainfo - wrong object type")
  63. check_info(message.get('info'), check_paths)
  64. if type(message.get('announce')) != str and type(message.get('nodes')) != list:
  65. raise BTFailure, _("bad metainfo - no announce URL string")
  66. if message.has_key('title') and type(message.get('title')) != str:
  67. raise BTFailure, _("bad metainfo - bad title - should be a string" )
  68. if message.has_key('nodes'):
  69. check_nodes(message.get('nodes'))
  70. def check_nodes(nodes):
  71. ## note, these strings need changing
  72. for node in nodes:
  73. if type(node) != list:
  74. raise BTFailure, _("bad metainfo - node is not a list")
  75. if len(node) != 2:
  76. raise BTFailure, _("bad metainfo - node list must have only two elements")
  77. host, port = node
  78. if type(host) != str:
  79. raise BTFailure, _("bad metainfo - node host must be a string")
  80. if type(port) != int:
  81. raise BTFailure, _("bad metainfo - node port must be an integer")