main.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. #!/usr/bin/env python3
  2. # -*- coding: utf8 -*-
  3. import os
  4. import sys
  5. import tarfile
  6. import sqlite3
  7. import requests
  8. from lxml import etree # What the fuck, Python: https://docs.python.org/3.9/library/xml.html#xml-vulnerabilities
  9. from http import HTTPStatus
  10. from datetime import datetime
  11. if __name__ == '__main__':
  12. versions = [
  13. '10.14.5',
  14. '10.14.4',
  15. '10.14.3',
  16. '10.14.2',
  17. '10.14.1',
  18. '10.14',
  19. '10.13.6',
  20. '10.13.5',
  21. '10.13.4',
  22. '10.13.3',
  23. '10.13.2',
  24. '10.13.1',
  25. '10.13',
  26. '10.12.6',
  27. '10.12.5',
  28. '10.12.4',
  29. '10.12.3',
  30. '10.12.2',
  31. '10.12.1',
  32. '10.12',
  33. '10.11.6',
  34. '10.11.5',
  35. '10.11.4',
  36. '10.11.3',
  37. '10.11.2',
  38. '10.11.1',
  39. '10.11',
  40. '10.10.5',
  41. '10.10.4',
  42. '10.10.3',
  43. '10.10.2',
  44. '10.10.1',
  45. '10.10',
  46. '10.9.5',
  47. '10.9.4',
  48. '10.9.3',
  49. '10.9.2',
  50. '10.9.1',
  51. '10.9',
  52. '10.8.5',
  53. '10.8.4',
  54. '10.8.3',
  55. '10.8.2',
  56. '10.8.1',
  57. '10.8',
  58. '10.7.5',
  59. '10.7.4',
  60. '10.7.3',
  61. '10.7.2',
  62. '10.7.1',
  63. '10.7',
  64. '10.6.8',
  65. '10.6.7',
  66. '10.6.6',
  67. '10.6.5',
  68. '10.6.4',
  69. '10.6.3',
  70. '10.6.2',
  71. '10.6.1',
  72. '10.6',
  73. '10.5.8',
  74. '10.5.7',
  75. '10.5.6',
  76. '10.5.5',
  77. '10.5.4',
  78. '10.5.3',
  79. '10.5.2',
  80. '10.5.1',
  81. '10.5',
  82. '10.4.11.x86',
  83. '10.4.11.ppc',
  84. '10.4.10.x86',
  85. '10.4.10.ppc',
  86. '10.4.9.x86',
  87. '10.4.9.ppc',
  88. '10.4.8.ppc',
  89. '10.4.8.x86',
  90. '10.4.7.ppc',
  91. '10.4.7.x86',
  92. '10.4.6.ppc',
  93. '10.4.6.x86',
  94. '10.4.5.x86',
  95. '10.4.5.ppc',
  96. '10.4.4.x86',
  97. '10.4.4.ppc',
  98. '10.4.3',
  99. '10.4.2',
  100. '10.4.1',
  101. '10.4',
  102. '10.3.9',
  103. '10.3.8',
  104. '10.3.7',
  105. '10.3.6',
  106. '10.3.5',
  107. '10.3.4',
  108. '10.3.3',
  109. '10.3.2',
  110. '10.3.1',
  111. '10.3',
  112. '10.2.8',
  113. '10.2.8.G5',
  114. '10.2.7',
  115. '10.2.6',
  116. '10.2.5',
  117. '10.2.4',
  118. '10.2.3',
  119. '10.2.2',
  120. '10.2.1',
  121. '10.2',
  122. '10.1.5',
  123. '10.1.4',
  124. '10.1.3',
  125. '10.1.2',
  126. '10.1.1',
  127. '10.1',
  128. '10.0.4',
  129. '10.0.3',
  130. '10.0.2',
  131. '10.0.1',
  132. '10.0',
  133. ]
  134. attributes = {
  135. 'OpenSourceImportDate': 'imported',
  136. 'OpenSourceLicense': 'license',
  137. 'OpenSourceLicenseFile': 'license_file',
  138. 'OpenSourceModifications': 'modifications',
  139. 'OpenSourceProject': 'name',
  140. 'OpenSourceSHA1': 'sha1',
  141. 'OpenSourceURL': 'url',
  142. 'OpenSourceVersion': 'version',
  143. 'OpenSourceWebsite': 'website',
  144. }
  145. db = sqlite3.connect('openapple.db')
  146. c = db.cursor()
  147. c.execute("""
  148. CREATE TABLE IF NOT EXISTS `projects` (
  149. `id` INTEGER PRIMARY KEY AUTOINCREMENT,
  150. `macos` TEXT NOT NULL,
  151. `name` TEXT NOT NULL,
  152. `build` TEXT NOT NULL,
  153. `modified` TEXT NOT NULL,
  154. `done` INT NOT NULL DEFAULT 0,
  155. UNIQUE(`macos`, `name`)
  156. )
  157. """)
  158. c.execute("""
  159. CREATE TABLE IF NOT EXISTS `opensource` (
  160. `id` INTEGER PRIMARY KEY AUTOINCREMENT,
  161. `project_id` INTEGER NOT NULL,
  162. `macos` TEXT NOT NULL,
  163. `name` TEXT,
  164. `imported` TEXT,
  165. `license` TEXT,
  166. `license_file` TEXT,
  167. `modifications` TEXT,
  168. `sha1` TEXT,
  169. `url` TEXT,
  170. `version` TEXT,
  171. `website` TEXT,
  172. UNIQUE(`macos`, `name`)
  173. )
  174. """)
  175. db.commit()
  176. for version in versions:
  177. main = requests.get('https://opensource.apple.com/plist/macos-%s.plist' % version.replace('.', ''))
  178. if main.status_code == HTTPStatus.OK:
  179. projectList = etree.fromstring(main.content)[0].find('dict')
  180. for i, child in enumerate(projectList):
  181. if child.tag != 'key':
  182. continue
  183. name = child.text
  184. # Skip project if done in db
  185. c.execute('SELECT COUNT(*) FROM `projects` WHERE `name`=(?) AND `done`=TRUE', (name, ))
  186. if c.fetchone()[0]:
  187. continue
  188. buildVersion = projectList[i+1].find('string').text
  189. tar = requests.get('https://opensource.apple.com/tarballs/%s/%s-%s.tar.gz' % (name, name, buildVersion))
  190. if tar.status_code == HTTPStatus.OK:
  191. with open('temp.tar.gz', 'wb') as f:
  192. f.write(tar.content)
  193. else:
  194. print('Error! %s' % name)
  195. continue
  196. tar = tarfile.open('temp.tar.gz')
  197. members = tar.getmembers()
  198. lastModified = datetime.utcfromtimestamp(int(members[0].get_info()['mtime'])).strftime('%Y-%m-%d %H:%M:%S')
  199. try:
  200. c.execute('INSERT INTO `projects` (`macos`, `name`, `build`, `modified`) VALUES (?, ?, ?, ?) ', (version, name, buildVersion, lastModified))
  201. db.commit()
  202. except sqlite3.IntegrityError:
  203. pass
  204. finally:
  205. c.execute('SELECT `id` FROM `projects` WHERE `name`=(?)', (name, ))
  206. projectId = c.fetchone()[0]
  207. plists = [member for member in members if '.plist' in member.name or '.partial' in member.name]
  208. for member in plists:
  209. try:
  210. plist = etree.fromstring(tar.extractfile(member).read())
  211. if plist.tag != 'dict':
  212. opensource = plist.find('dict')
  213. if opensource == None:
  214. opensource = plist.find('array')
  215. if opensource == None:
  216. continue
  217. opensource = opensource.find('dict')
  218. if opensource == None:
  219. continue
  220. else:
  221. opensource = plist
  222. except etree.XMLSyntaxError:
  223. # Skip invalid xml files
  224. continue
  225. relevant = {}
  226. for index, attribute in enumerate(opensource):
  227. if attribute.tag != 'key':
  228. continue
  229. if attribute.text in attributes.keys():
  230. relevant[attributes[attribute.text]] = opensource[index+1].text
  231. if not relevant:
  232. continue
  233. relevant['macos'] = version
  234. relevant['project_id'] = projectId
  235. for attribute in attributes.values():
  236. if not attribute in relevant:
  237. relevant[attribute] = ''
  238. try:
  239. c.execute('INSERT INTO opensource VALUES (NULL, :macos, :project_id, :name, :imported, :license, :license_file, :modifications, :sha1, :url, :version, :website)', relevant)
  240. db.commit()
  241. except sqlite3.IntegrityError:
  242. pass
  243. c.execute('UPDATE `projects` SET `done`=TRUE WHERE `id`=(?)', (projectId, ))
  244. db.commit()
  245. os.remove('temp.tar.gz')