Advertisement
Guest User

Untitled

a guest
May 22nd, 2017
50
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.41 KB | None | 0 0
  1. import re
  2.  
  3. __all__ = ["Header", "IPParseError", "IPRange", "IPRecord", "Report", "ServerBlacklist"]
  4.  
  5.  
  6. class Header(object):
  7. def __init__(self, text, indent=" "):
  8. self.text = text
  9. self.indent = indent
  10.  
  11. def _dump_to_lines(self):
  12. return ["//{}{}".format(self.indent, line) for line in self.text.splitlines()]
  13.  
  14.  
  15. class IPParseError(Exception):
  16. pass
  17.  
  18.  
  19. class IPRange(object):
  20. def __init__(self, text):
  21. self.text = text
  22. self._low_address, self._high_address = IPRange._parse_ip_range(text)
  23.  
  24. @staticmethod
  25. def _parse_ip(ip):
  26. match = re.match(r"^(\d+)\.(\d+)\.(\d+)\.(\d+)$", ip)
  27. b1, b2, b3, b4 = map(int, match.groups())
  28. return (b1 << 24) + (b2 << 16) + (b3 << 8) + b4
  29.  
  30. @staticmethod
  31. def _parse_ip_range(text):
  32. if re.match(r"^\d+\.\d+\.\d+\.\d+$", text) is not None:
  33. address = IPRange._parse_ip(text)
  34. return address, address
  35.  
  36. subnet_match = re.match(r"^(\d+\.\d+\.\d+\.\d+)\s*/\s*(\d+)$", text)
  37.  
  38. if subnet_match is not None:
  39. ip_string, subnet_string = subnet_match.groups()
  40. ip_address = IPRange._parse_ip(ip_string)
  41. subnet = int(subnet_string)
  42. erase_bits = 32 - subnet
  43. low_address = (ip_address >> erase_bits) << erase_bits
  44. high_address = low_address + (1 << erase_bits) - 1
  45. return low_address, high_address
  46.  
  47. range_match = re.match(r"^(\d+\.\d+\.\d+\.\d+)\s*\-\s*(\d+\.\d+\.\d+\.\d+)$", text)
  48.  
  49. if range_match is not None:
  50. low_string, high_string = range_match.groups()
  51. return IPRange._parse_ip(low_string), IPRange._parse_ip(high_string)
  52.  
  53. raise IPParseError("{!r} is not a valid IP range".format(text))
  54.  
  55. def matches(self, ip):
  56. normalized_ip = re.sub(r"\.x$", r".0", ip)
  57. address = self._parse_ip(normalized_ip)
  58.  
  59. if ip == normalized_ip:
  60. return self._low_address <= address <= self._high_address
  61. else:
  62. return self._low_address <= (address + 255) and address <= self._high_address
  63.  
  64.  
  65. class IPRecord(object):
  66. def __init__(self, ip_range, comment=None, enabled=True):
  67. self.ip_range = ip_range
  68. self.comment = comment
  69. self.enabled = enabled
  70.  
  71. def _dump_to_lines(self):
  72. line = self.ip_range.text
  73.  
  74. if self.comment is not None:
  75. line = "{} // {}".format(line, self.comment)
  76.  
  77. if not self.enabled:
  78. line = "// {}".format(line)
  79.  
  80. return [line]
  81.  
  82.  
  83. class Report(object):
  84. def __init__(self, fields, ip_records):
  85. self.fields = fields
  86. self.ip_records = ip_records
  87.  
  88. def _dump_field_to_lines(self, field):
  89. value = self.fields[field]
  90. return ["// {}: {}".format(field, line) for line in value.splitlines()]
  91.  
  92. def _dump_to_lines(self):
  93. lines = []
  94. main_fields = ["Name", "Ban Date", "Ban Reason", "Proof", "Server", "Added by", "Extra"]
  95.  
  96. for main_field in main_fields:
  97. if main_field in self.fields:
  98. lines.extend(self._dump_field_to_lines(main_field))
  99.  
  100. for field in sorted(self.fields.keys()):
  101. if field not in main_fields:
  102. lines.extend(self._dump_field_to_lines(field))
  103.  
  104. for ip_record in sorted(self.ip_records, key=lambda ip_record: ip_record.ip_range._low_address):
  105. lines.extend(ip_record._dump_to_lines())
  106.  
  107. return lines
  108.  
  109.  
  110. class ServerBlacklistParser(object):
  111. def __init__(self, text):
  112. self.lines = text.splitlines()
  113. self.line_index = -1
  114. self.line_content = None
  115. self.line_comment = None
  116. self.line_enabled = None
  117. self.skip_line()
  118.  
  119. @staticmethod
  120. def split_line(line):
  121. if "//" not in line:
  122. return line.strip(), None, True
  123.  
  124. content, comment = line.split("//", 1)
  125. content = content.strip()
  126.  
  127. if content != "":
  128. return content, comment, True
  129.  
  130. if "//" in comment:
  131. content, nested_comment = comment.split("//", 1)
  132. else:
  133. content = comment
  134. nested_comment = None
  135.  
  136. content = content.strip()
  137.  
  138. try:
  139. IPRange(content)
  140. except IPParseError:
  141. return "", comment, True
  142. else:
  143. return content, nested_comment, False
  144.  
  145. def skip_line(self):
  146. self.line_index += 1
  147.  
  148. if self.at_eof():
  149. self.line_content = None
  150. self.line_comment = None
  151. self.line_enabled = None
  152. return
  153.  
  154. line = self.lines[self.line_index]
  155. self.line_content, self.line_comment, self.line_enabled = ServerBlacklistParser.split_line(line)
  156.  
  157. def at_eof(self):
  158. return self.line_index >= len(self.lines)
  159.  
  160. def line_is_empty(self):
  161. return self.line_content == "" and self.line_comment is None
  162.  
  163. def line_is_pure_comment(self):
  164. return self.line_content == "" and self.line_comment is not None
  165.  
  166. def line_has_content(self):
  167. return self.line_content != "" and self.line_content is not None
  168.  
  169. @staticmethod
  170. def comments_to_fields(comments):
  171. fields = {}
  172.  
  173. for comment in comments:
  174. if ":" in comment:
  175. field, value = comment.split(":", 1)
  176. field = field.strip().title()
  177. value = value.strip()
  178.  
  179. if field == "Date":
  180. field = "Ban Date"
  181. elif field == "Reason":
  182. field = "Ban Reason"
  183. elif field == "Evidence":
  184. field = "Proof"
  185. else:
  186. field = "Extra"
  187. value = comment.strip()
  188.  
  189. if value == "":
  190. value = "(empty)"
  191.  
  192. if field in fields:
  193. fields[field] = "{}\n{}".format(fields[field], value)
  194. else:
  195. fields[field] = value
  196.  
  197. return fields
  198.  
  199. def parse_item(self):
  200. while self.line_is_empty():
  201. self.skip_line()
  202.  
  203. if self.at_eof():
  204. return
  205.  
  206. pure_comments = []
  207.  
  208. while self.line_is_pure_comment():
  209. pure_comments.append(self.line_comment)
  210. self.skip_line()
  211.  
  212. if self.at_eof() or self.line_is_empty():
  213. if len(pure_comments) > 0:
  214. return Header("\n".join(pure_comments), indent="")
  215. else:
  216. return
  217.  
  218. ip_records = []
  219.  
  220. while self.line_has_content():
  221. try:
  222. ip_range = IPRange(self.line_content)
  223. except IPParseError as e:
  224. pass
  225. else:
  226. record_comment = None if self.line_comment is None else self.line_comment.strip()
  227. ip_records.append(IPRecord(ip_range, record_comment, self.line_enabled))
  228.  
  229. self.skip_line()
  230.  
  231. if len(ip_records) > 0:
  232. return Report(ServerBlacklistParser.comments_to_fields(pure_comments), ip_records)
  233. else:
  234. return
  235.  
  236. def parse_items(self):
  237. items = []
  238.  
  239. while not self.at_eof():
  240. item = self.parse_item()
  241.  
  242. if item is not None:
  243. items.append(item)
  244.  
  245. return items
  246.  
  247.  
  248. class ServerBlacklist(object):
  249. def __init__(self, items):
  250. self.items = items
  251.  
  252. def dump_to_string(self):
  253. return "\n".join("\n".join(item._dump_to_lines()) + "\n" for item in self.items)
  254.  
  255. @classmethod
  256. def load_from_string(cls, text):
  257. return cls(ServerBlacklistParser(text).parse_items())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement