├── .python-version ├── package_control ├── http │ ├── __init__.py │ ├── debuggable_https_response.py │ ├── invalid_certificate_exception.py │ ├── debuggable_http_handler.py │ ├── validating_https_handler.py │ ├── debuggable_http_response.py │ ├── debuggable_http_connection.py │ └── persistent_handler.py ├── clients │ ├── __init__.py │ ├── client_exception.py │ └── readme_client.py ├── upgraders │ ├── __init__.py │ ├── vcs_upgrader.py │ └── hg_upgrader.py ├── deps │ ├── oscrypto │ │ ├── _mac │ │ │ ├── __init__.py │ │ │ ├── _common_crypto.py │ │ │ ├── _common_crypto_ctypes.py │ │ │ ├── _common_crypto_cffi.py │ │ │ └── _security.py │ │ ├── _win │ │ │ ├── __init__.py │ │ │ ├── _kernel32.py │ │ │ ├── _decode.py │ │ │ ├── _kernel32_cffi.py │ │ │ ├── _kernel32_ctypes.py │ │ │ ├── _crypt32.py │ │ │ ├── _secur32_cffi.py │ │ │ ├── _secur32.py │ │ │ └── _cng_cffi.py │ │ ├── _linux_bsd │ │ │ ├── __init__.py │ │ │ └── trust_list.py │ │ ├── _openssl │ │ │ ├── __init__.py │ │ │ ├── _libssl.py │ │ │ ├── _libssl_cffi.py │ │ │ └── _libcrypto.py │ │ ├── version.py │ │ ├── keys.py │ │ ├── tls.py │ │ ├── _int.py │ │ ├── _types.py │ │ ├── _rand.py │ │ ├── _errors.py │ │ ├── util.py │ │ ├── symmetric.py │ │ ├── _asn1.py │ │ ├── errors.py │ │ └── _pkcs5.py │ ├── asn1crypto │ │ ├── version.py │ │ ├── _int.py │ │ ├── _types.py │ │ ├── _errors.py │ │ ├── __init__.py │ │ ├── pdf.py │ │ └── csr.py │ └── __init__.py ├── __init__.py ├── downloaders │ ├── downloader_exception.py │ ├── non_http_error.py │ ├── binary_not_found_error.py │ ├── http_error.py │ ├── win_downloader_exception.py │ ├── oscrypto_downloader_exception.py │ ├── non_clean_exit_error.py │ ├── rate_limit_exception.py │ ├── limiting_downloader.py │ ├── __init__.py │ ├── decoding_downloader.py │ ├── basic_auth_downloader.py │ └── cli_downloader.py ├── commands │ ├── create_package_command.py │ ├── discover_packages_command.py │ ├── package_control_insert_command.py │ ├── package_control_message_command.py │ ├── package_control_disable_debug_mode_command.py │ ├── package_control_enable_debug_mode_command.py │ ├── satisfy_packages_command.py │ ├── upgrade_all_packages_command.py │ ├── list_unmanaged_packages_command.py │ ├── remove_packages_command.py │ ├── new_template_command.py │ ├── clear_package_cache_command.py │ ├── remove_repository_command.py │ ├── enable_package_command.py │ ├── disable_package_command.py │ ├── enable_packages_command.py │ ├── remove_package_command.py │ ├── satisfy_libraries_command.py │ ├── revert_package_command.py │ ├── install_packages_command.py │ ├── upgrade_packages_command.py │ ├── install_package_command.py │ ├── disable_packages_command.py │ ├── remove_channel_command.py │ ├── list_packages_command.py │ ├── add_channel_command.py │ ├── add_repository_command.py │ ├── upgrade_package_command.py │ ├── __init__.py │ └── list_available_libraries_command.py ├── providers │ ├── __init__.py │ ├── schema_version.py │ ├── provider_exception.py │ └── base_repository_provider.py ├── console_write.py ├── show_error.py ├── settings.py ├── text.py ├── selectors.py ├── processes.py ├── activity_indicator.py ├── http_cache.py ├── automatic_upgrader.py ├── events.py └── package_version.py ├── messages.json ├── unittesting.json ├── package-metadata.json ├── messages ├── 4.2.0.txt └── 4.0.0.txt ├── Main.sublime-menu ├── readme.md └── Default.sublime-commands /.python-version: -------------------------------------------------------------------------------- 1 | 3.8 -------------------------------------------------------------------------------- /package_control/http/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package_control/clients/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package_control/upgraders/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_mac/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_win/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_linux_bsd/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_openssl/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package_control/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = "4.2.2" 2 | __version_info__ = (4, 2, 2) 3 | -------------------------------------------------------------------------------- /messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "4.0.0": "messages/4.0.0.txt", 3 | "4.2.0": "messages/4.2.0.txt" 4 | } 5 | -------------------------------------------------------------------------------- /package_control/clients/client_exception.py: -------------------------------------------------------------------------------- 1 | class ClientException(Exception): 2 | 3 | """If a client could not fetch information""" 4 | -------------------------------------------------------------------------------- /package_control/downloaders/downloader_exception.py: -------------------------------------------------------------------------------- 1 | class DownloaderException(Exception): 2 | 3 | """If a downloader could not download a URL""" 4 | -------------------------------------------------------------------------------- /unittesting.json: -------------------------------------------------------------------------------- 1 | { 2 | "tests_dir": "package_control/tests", 3 | "pattern": "test*.py", 4 | "reload_package_on_testing": false, 5 | "verbosity": 1 6 | } -------------------------------------------------------------------------------- /package_control/downloaders/non_http_error.py: -------------------------------------------------------------------------------- 1 | class NonHttpError(Exception): 2 | 3 | """If a downloader had a non-clean exit, but it was not due to an HTTP error""" 4 | -------------------------------------------------------------------------------- /package_control/downloaders/binary_not_found_error.py: -------------------------------------------------------------------------------- 1 | class BinaryNotFoundError(Exception): 2 | 3 | """If a necessary executable is not found in the PATH on the system""" 4 | -------------------------------------------------------------------------------- /package_control/deps/asn1crypto/version.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | 5 | __version__ = '1.5.1' 6 | __version_info__ = (1, 5, 1) 7 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/version.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | 5 | __version__ = '1.3.0' 6 | __version_info__ = (1, 3, 0) 7 | -------------------------------------------------------------------------------- /package-metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Package Control", 3 | "version": "4.2.2", 4 | "description": "A full-featured package manager", 5 | "platforms": ["*"], 6 | "sublime_text": ">=3143", 7 | "url": "https://packagecontrol.io" 8 | } 9 | -------------------------------------------------------------------------------- /package_control/downloaders/http_error.py: -------------------------------------------------------------------------------- 1 | class HttpError(Exception): 2 | 3 | """If a downloader was able to download a URL, but the result was not a 200 or 304""" 4 | 5 | def __init__(self, message, code): 6 | self.code = code 7 | super(HttpError, self).__init__(message) 8 | -------------------------------------------------------------------------------- /package_control/http/debuggable_https_response.py: -------------------------------------------------------------------------------- 1 | from .debuggable_http_response import DebuggableHTTPResponse 2 | 3 | 4 | class DebuggableHTTPSResponse(DebuggableHTTPResponse): 5 | 6 | """ 7 | A version of DebuggableHTTPResponse that sets the debug protocol to HTTPS 8 | """ 9 | 10 | _debug_protocol = 'HTTPS' 11 | -------------------------------------------------------------------------------- /package_control/downloaders/win_downloader_exception.py: -------------------------------------------------------------------------------- 1 | from .downloader_exception import DownloaderException 2 | 3 | 4 | class WinDownloaderException(DownloaderException): 5 | 6 | """ 7 | If the WinInetDownloader ran into a windows-specific error. The means we 8 | should retry with the UrllibDownloader. 9 | """ 10 | 11 | pass 12 | -------------------------------------------------------------------------------- /package_control/commands/create_package_command.py: -------------------------------------------------------------------------------- 1 | import sublime_plugin 2 | 3 | from ..package_creator import PackageCreator 4 | 5 | 6 | class CreatePackageCommand(sublime_plugin.ApplicationCommand): 7 | 8 | """ 9 | Command to create a regular .sublime-package file 10 | """ 11 | 12 | def run(self): 13 | PackageCreator().run() 14 | -------------------------------------------------------------------------------- /package_control/commands/discover_packages_command.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | 5 | class DiscoverPackagesCommand(sublime_plugin.ApplicationCommand): 6 | 7 | """ 8 | A command that opens the Package Control website 9 | """ 10 | 11 | def run(self): 12 | sublime.run_command('open_url', {'url': 'https://packagecontrol.io/#discover'}) 13 | -------------------------------------------------------------------------------- /package_control/downloaders/oscrypto_downloader_exception.py: -------------------------------------------------------------------------------- 1 | from .downloader_exception import DownloaderException 2 | 3 | 4 | class OscryptoDownloaderException(DownloaderException): 5 | 6 | """ 7 | If the OscryptoDownloader ran into an error. Most likely a non-HTTPS 8 | connection or non-HTTPS proxy. The means we should retry with the 9 | UrllibDownloader. 10 | """ 11 | 12 | pass 13 | -------------------------------------------------------------------------------- /package_control/commands/package_control_insert_command.py: -------------------------------------------------------------------------------- 1 | import sublime_plugin 2 | 3 | 4 | class PackageControlInsertCommand(sublime_plugin.TextCommand): 5 | 6 | """ 7 | A command used by the test runner to display output in the output panel 8 | """ 9 | 10 | def run(self, edit, string=''): 11 | self.view.insert(edit, self.view.size(), string) 12 | self.view.show(self.view.size(), True) 13 | -------------------------------------------------------------------------------- /package_control/downloaders/non_clean_exit_error.py: -------------------------------------------------------------------------------- 1 | class NonCleanExitError(Exception): 2 | 3 | """ 4 | When an subprocess does not exit cleanly 5 | 6 | :param returncode: 7 | The command line integer return code of the subprocess 8 | """ 9 | 10 | def __init__(self, returncode): 11 | self.returncode = returncode 12 | 13 | def __str__(self): 14 | return str(self.returncode) 15 | -------------------------------------------------------------------------------- /package_control/deps/asn1crypto/_int.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | 5 | def fill_width(bytes_, width): 6 | """ 7 | Ensure a byte string representing a positive integer is a specific width 8 | (in bytes) 9 | 10 | :param bytes_: 11 | The integer byte string 12 | 13 | :param width: 14 | The desired width as an integer 15 | 16 | :return: 17 | A byte string of the width specified 18 | """ 19 | 20 | while len(bytes_) < width: 21 | bytes_ = b'\x00' + bytes_ 22 | return bytes_ 23 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_mac/_common_crypto.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .. import ffi 5 | 6 | if ffi() == 'cffi': 7 | from ._common_crypto_cffi import CommonCrypto 8 | else: 9 | from ._common_crypto_ctypes import CommonCrypto 10 | 11 | 12 | __all__ = [ 13 | 'CommonCrypto', 14 | 'CommonCryptoConst', 15 | ] 16 | 17 | 18 | class CommonCryptoConst(): 19 | kCCPBKDF2 = 2 20 | kCCPRFHmacAlgSHA1 = 1 21 | kCCPRFHmacAlgSHA224 = 2 22 | kCCPRFHmacAlgSHA256 = 3 23 | kCCPRFHmacAlgSHA384 = 4 24 | kCCPRFHmacAlgSHA512 = 5 25 | -------------------------------------------------------------------------------- /package_control/http/invalid_certificate_exception.py: -------------------------------------------------------------------------------- 1 | from http.client import HTTPException 2 | from urllib.error import URLError 3 | 4 | 5 | class InvalidCertificateException(HTTPException, URLError): 6 | 7 | """ 8 | An exception for when an SSL certification is not valid for the URL 9 | it was presented for. 10 | """ 11 | 12 | def __init__(self, host, cert, reason): 13 | self.host = host 14 | self.cert = cert 15 | self.reason = reason.rstrip() 16 | message = 'Host %s returned an invalid certificate (%s) %s' % (self.host, self.reason, self.cert) 17 | HTTPException.__init__(self, message.rstrip()) 18 | -------------------------------------------------------------------------------- /package_control/commands/package_control_message_command.py: -------------------------------------------------------------------------------- 1 | import sublime_plugin 2 | 3 | 4 | class PackageControlMessageCommand(sublime_plugin.TextCommand): 5 | view_name = "Package Control Messages" 6 | 7 | def run(self, edit, message): 8 | if self.view.name() != self.view_name: 9 | return 10 | 11 | eof = self.view.size() 12 | if eof == 0: 13 | message = "{}\n{}\n{}".format( 14 | self.view_name, "=" * len(self.view_name), message 15 | ) 16 | 17 | self.view.set_read_only(False) 18 | self.view.insert(edit, eof, message) 19 | self.view.set_read_only(True) 20 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/keys.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from . import backend 5 | from ._asymmetric import parse_certificate, parse_private, parse_public 6 | 7 | 8 | _backend = backend() 9 | 10 | 11 | if _backend == 'mac': 12 | from ._mac.asymmetric import parse_pkcs12 13 | elif _backend == 'win' or _backend == 'winlegacy': 14 | from ._win.asymmetric import parse_pkcs12 15 | else: 16 | from ._openssl.asymmetric import parse_pkcs12 17 | 18 | 19 | __all__ = [ 20 | 'parse_certificate', 21 | 'parse_pkcs12', 22 | 'parse_private', 23 | 'parse_public', 24 | ] 25 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/tls.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from . import backend 5 | 6 | 7 | _backend = backend() 8 | 9 | 10 | if _backend == 'mac': 11 | from ._mac.tls import ( 12 | TLSSession, 13 | TLSSocket, 14 | ) 15 | 16 | elif _backend == 'win' or _backend == 'winlegacy': 17 | from ._win.tls import ( 18 | TLSSession, 19 | TLSSocket, 20 | ) 21 | 22 | else: 23 | from ._openssl.tls import ( 24 | TLSSession, 25 | TLSSocket, 26 | ) 27 | 28 | 29 | __all__ = [ 30 | 'TLSSession', 31 | 'TLSSocket', 32 | ] 33 | -------------------------------------------------------------------------------- /package_control/providers/__init__.py: -------------------------------------------------------------------------------- 1 | from .bitbucket_repository_provider import BitBucketRepositoryProvider 2 | from .github_repository_provider import GitHubRepositoryProvider 3 | from .github_user_provider import GitHubUserProvider 4 | from .gitlab_repository_provider import GitLabRepositoryProvider 5 | from .gitlab_user_provider import GitLabUserProvider 6 | from .json_repository_provider import JsonRepositoryProvider 7 | 8 | from .channel_provider import ChannelProvider 9 | 10 | 11 | REPOSITORY_PROVIDERS = [ 12 | BitBucketRepositoryProvider, 13 | GitHubRepositoryProvider, 14 | GitHubUserProvider, 15 | GitLabRepositoryProvider, 16 | GitLabUserProvider, 17 | JsonRepositoryProvider 18 | ] 19 | 20 | CHANNEL_PROVIDERS = [ChannelProvider] 21 | -------------------------------------------------------------------------------- /package_control/commands/package_control_disable_debug_mode_command.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | from ..settings import pc_settings_filename 5 | from ..show_error import show_message 6 | 7 | 8 | class PackageControlDisableDebugModeCommand(sublime_plugin.ApplicationCommand): 9 | def run(self): 10 | settings_file = pc_settings_filename() 11 | settings = sublime.load_settings(settings_file) 12 | settings.set('debug', False) 13 | sublime.save_settings(settings_file) 14 | 15 | show_message('Debug mode has been disabled') 16 | 17 | def is_visible(self): 18 | return sublime.load_settings(pc_settings_filename()).get('debug', False) 19 | 20 | def is_enabled(self): 21 | return self.is_visible() 22 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_int.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | Function to fill ensure integers converted to a byte string are a specific 5 | width. Exports the following items: 6 | 7 | - fill_width() 8 | """ 9 | 10 | from __future__ import unicode_literals, division, absolute_import, print_function 11 | 12 | 13 | __all__ = [ 14 | 'fill_width', 15 | ] 16 | 17 | 18 | def fill_width(bytes_, width): 19 | """ 20 | Ensure a byte string representing a positive integer is a specific width 21 | (in bytes) 22 | 23 | :param bytes_: 24 | The integer byte string 25 | 26 | :param width: 27 | The desired width as an integer 28 | 29 | :return: 30 | A byte string of the width specified 31 | """ 32 | 33 | while len(bytes_) < width: 34 | bytes_ = b'\x00' + bytes_ 35 | return bytes_ 36 | -------------------------------------------------------------------------------- /package_control/downloaders/rate_limit_exception.py: -------------------------------------------------------------------------------- 1 | from .downloader_exception import DownloaderException 2 | 3 | 4 | class RateLimitException(DownloaderException): 5 | 6 | """ 7 | An exception for when the rate limit of an API has been exceeded. 8 | """ 9 | 10 | def __init__(self, domain, limit): 11 | self.domain = domain 12 | self.limit = limit 13 | 14 | def __str__(self): 15 | return 'Hit rate limit of %s for %s.' % (self.limit, self.domain) 16 | 17 | 18 | class RateLimitSkipException(DownloaderException): 19 | 20 | """ 21 | An exception for when skipping requests due to rate limit of an API has been exceeded. 22 | """ 23 | 24 | def __init__(self, domain): 25 | self.domain = domain 26 | 27 | def __str__(self): 28 | return 'Skipping %s due to rate limit.' % self.domain 29 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_mac/_common_crypto_ctypes.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from ctypes import CDLL, c_uint32, c_char_p, c_size_t, c_int, c_uint 5 | 6 | from .._ffi import FFIEngineError 7 | 8 | 9 | __all__ = [ 10 | 'CommonCrypto', 11 | ] 12 | 13 | 14 | common_crypto_path = '/usr/lib/system/libcommonCrypto.dylib' 15 | 16 | CommonCrypto = CDLL(common_crypto_path, use_errno=True) 17 | 18 | try: 19 | CommonCrypto.CCKeyDerivationPBKDF.argtypes = [ 20 | c_uint32, 21 | c_char_p, 22 | c_size_t, 23 | c_char_p, 24 | c_size_t, 25 | c_uint32, 26 | c_uint, 27 | c_char_p, 28 | c_size_t 29 | ] 30 | CommonCrypto.CCKeyDerivationPBKDF.restype = c_int 31 | except (AttributeError): 32 | raise FFIEngineError('Error initializing ctypes') 33 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_mac/_common_crypto_cffi.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .._ffi import register_ffi 5 | 6 | from cffi import FFI 7 | 8 | 9 | __all__ = [ 10 | 'CommonCrypto', 11 | ] 12 | 13 | 14 | ffi = FFI() 15 | ffi.cdef(""" 16 | typedef uint32_t CCPBKDFAlgorithm; 17 | 18 | typedef uint32_t CCPseudoRandomAlgorithm; 19 | typedef unsigned int uint; 20 | 21 | int CCKeyDerivationPBKDF(CCPBKDFAlgorithm algorithm, const char *password, size_t passwordLen, 22 | const char *salt, size_t saltLen, CCPseudoRandomAlgorithm prf, uint rounds, 23 | char *derivedKey, size_t derivedKeyLen); 24 | """) 25 | 26 | common_crypto_path = '/usr/lib/system/libcommonCrypto.dylib' 27 | 28 | CommonCrypto = ffi.dlopen(common_crypto_path) 29 | register_ffi(CommonCrypto, ffi) 30 | -------------------------------------------------------------------------------- /package_control/commands/package_control_enable_debug_mode_command.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | from ..settings import pc_settings_filename 5 | from ..show_error import show_message 6 | 7 | 8 | class PackageControlEnableDebugModeCommand(sublime_plugin.ApplicationCommand): 9 | def run(self): 10 | settings_file = pc_settings_filename() 11 | settings = sublime.load_settings(settings_file) 12 | settings.set('debug', True) 13 | sublime.save_settings(settings_file) 14 | 15 | show_message( 16 | ''' 17 | Debug mode has been enabled, a log of commands will be written 18 | to the Sublime Text console 19 | ''' 20 | ) 21 | 22 | def is_visible(self): 23 | return not sublime.load_settings(pc_settings_filename()).get('debug', False) 24 | 25 | def is_enabled(self): 26 | return self.is_visible() 27 | -------------------------------------------------------------------------------- /package_control/console_write.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from . import text 4 | 5 | 6 | def console_write(string, params=None, strip=True, indent=None, prefix=True): 7 | """ 8 | Writes a value to the Sublime Text console, formatting it for output via 9 | text.format() and then encoding unicode to utf-8 10 | 11 | :param string: 12 | The value to write 13 | 14 | :param params: 15 | Params to interpolate into the string using the % operator 16 | 17 | :param strip: 18 | If a single trailing newline should be stripped 19 | 20 | :param indent: 21 | If all lines should be indented by a set indent after being de-dented 22 | 23 | :param prefix: 24 | If the string "Package Control: " should be prefixed to the string 25 | """ 26 | 27 | string = text.format(str(string), params, strip=strip, indent=indent) 28 | 29 | if prefix: 30 | sys.stdout.write('Package Control: ') 31 | 32 | print(string) 33 | -------------------------------------------------------------------------------- /package_control/commands/satisfy_packages_command.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | import sublime_plugin 4 | 5 | from ..activity_indicator import ActivityIndicator 6 | from ..package_tasks import PackageTaskRunner 7 | 8 | 9 | class SatisfyPackagesCommand(sublime_plugin.ApplicationCommand): 10 | 11 | """ 12 | A command to sync ``installed_packages`` with filesystem. 13 | 14 | It installs missing packages, which are listed in ``installed_packages`` 15 | but are not present on filesystem. 16 | 17 | It removes managed packages, which are found on filesystem but are not 18 | present in ``installed_packages``. 19 | """ 20 | 21 | def run(self): 22 | 23 | def worker(): 24 | message = 'Satisfying packages...' 25 | with ActivityIndicator(message) as progress: 26 | installer = PackageTaskRunner() 27 | installer.satisfy_packages(progress) 28 | 29 | threading.Thread(target=worker).start() 30 | -------------------------------------------------------------------------------- /package_control/commands/upgrade_all_packages_command.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | import sublime_plugin 4 | 5 | from ..activity_indicator import ActivityIndicator 6 | from ..console_write import console_write 7 | from ..package_tasks import PackageTaskRunner 8 | 9 | 10 | class UpgradeAllPackagesCommand(sublime_plugin.ApplicationCommand): 11 | 12 | """ 13 | A command to automatically upgrade all installed packages that are 14 | upgradable. 15 | 16 | ```py 17 | sublime.run_command("upgrade_all_packages", {"unattended": False}) 18 | ``` 19 | """ 20 | 21 | def run(self, unattended=False): 22 | 23 | def worker(): 24 | message = 'Searching updates...' 25 | with ActivityIndicator(message) as progress: 26 | console_write(message) 27 | upgrader = PackageTaskRunner() 28 | upgrader.upgrade_packages(None, None, unattended, progress) 29 | 30 | threading.Thread(target=worker).start() 31 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_win/_kernel32.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .. import ffi 5 | from ._decode import _try_decode 6 | from .._types import str_cls 7 | 8 | if ffi() == 'cffi': 9 | from ._kernel32_cffi import kernel32, get_error 10 | else: 11 | from ._kernel32_ctypes import kernel32, get_error 12 | 13 | 14 | __all__ = [ 15 | 'handle_error', 16 | 'kernel32', 17 | ] 18 | 19 | 20 | def handle_error(result): 21 | """ 22 | Extracts the last Windows error message into a python unicode string 23 | 24 | :param result: 25 | A function result, 0 or None indicates failure 26 | 27 | :return: 28 | A unicode string error message 29 | """ 30 | 31 | if result: 32 | return 33 | 34 | _, error_string = get_error() 35 | 36 | if not isinstance(error_string, str_cls): 37 | error_string = _try_decode(error_string) 38 | 39 | raise OSError(error_string) 40 | -------------------------------------------------------------------------------- /package_control/downloaders/limiting_downloader.py: -------------------------------------------------------------------------------- 1 | from urllib.parse import urlparse 2 | 3 | from .rate_limit_exception import RateLimitException 4 | 5 | 6 | class LimitingDownloader: 7 | 8 | """ 9 | A base for downloaders that checks for rate limiting headers. 10 | """ 11 | 12 | def handle_rate_limit(self, headers, url): 13 | """ 14 | Checks the headers of a response object to make sure we are obeying the 15 | rate limit 16 | 17 | :param headers: 18 | The dict-like object that contains lower-cased headers 19 | 20 | :param url: 21 | The URL that was requested 22 | 23 | :raises: 24 | RateLimitException when the rate limit has been hit 25 | """ 26 | 27 | limit_remaining = headers.get('x-ratelimit-remaining', '1') 28 | limit = headers.get('x-ratelimit-limit', '1') 29 | 30 | if str(limit_remaining) == '0': 31 | hostname = urlparse(url).hostname 32 | raise RateLimitException(hostname, limit) 33 | -------------------------------------------------------------------------------- /package_control/http/debuggable_http_handler.py: -------------------------------------------------------------------------------- 1 | from urllib.request import HTTPHandler 2 | 3 | from .debuggable_http_connection import DebuggableHTTPConnection 4 | from .persistent_handler import PersistentHandler 5 | 6 | 7 | class DebuggableHTTPHandler(PersistentHandler, HTTPHandler): 8 | 9 | """ 10 | A custom HTTPHandler that formats debugging info for Sublime Text 11 | """ 12 | 13 | def __init__(self, debuglevel=0, debug=False, **kwargs): 14 | # This is a special value that will not trigger the standard debug 15 | # functionality, but custom code where we can format the output 16 | if debug: 17 | self._debuglevel = 5 18 | else: 19 | self._debuglevel = debuglevel 20 | 21 | def http_open(self, req): 22 | def http_class_wrapper(host, **kwargs): 23 | if 'debuglevel' not in kwargs: 24 | kwargs['debuglevel'] = self._debuglevel 25 | return DebuggableHTTPConnection(host, **kwargs) 26 | 27 | return self.do_open(http_class_wrapper, req) 28 | -------------------------------------------------------------------------------- /package_control/upgraders/vcs_upgrader.py: -------------------------------------------------------------------------------- 1 | from ..cmd import Cli 2 | 3 | 4 | class VcsUpgrader(Cli): 5 | 6 | """ 7 | Base class for updating packages that are a version control repository on local disk 8 | 9 | :param vcs_binary_paths: 10 | The full filesystem path to the executable for the version control 11 | system. May be set to None to allow the code to try and find it. 12 | 13 | :param update_command: 14 | The command to pass to the version control executable to update the 15 | repository. 16 | 17 | :param working_copy: 18 | The local path to the working copy/package directory 19 | 20 | :param cache_length: 21 | The lenth of time to cache if incoming changesets are available 22 | """ 23 | 24 | def __init__(self, vcs_binary_paths, update_command, working_copy, cache_length, debug): 25 | self.update_command = update_command 26 | self.working_copy = working_copy 27 | self.cache_length = cache_length 28 | super(VcsUpgrader, self).__init__(vcs_binary_paths, debug) 29 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_types.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import sys 5 | import inspect 6 | 7 | 8 | if sys.version_info < (3,): 9 | str_cls = unicode # noqa 10 | byte_cls = str 11 | int_types = (int, long) # noqa 12 | 13 | def bytes_to_list(byte_string): 14 | return [ord(b) for b in byte_string] 15 | 16 | else: 17 | str_cls = str 18 | byte_cls = bytes 19 | int_types = (int,) 20 | 21 | bytes_to_list = list 22 | 23 | 24 | def type_name(value): 25 | """ 26 | Returns a user-readable name for the type of an object 27 | 28 | :param value: 29 | A value to get the type name of 30 | 31 | :return: 32 | A unicode string of the object's type name 33 | """ 34 | 35 | if inspect.isclass(value): 36 | cls = value 37 | else: 38 | cls = value.__class__ 39 | if cls.__module__ in set(['builtins', '__builtin__']): 40 | return cls.__name__ 41 | return '%s.%s' % (cls.__module__, cls.__name__) 42 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_win/_decode.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import locale 5 | 6 | from .._types import str_cls 7 | 8 | 9 | _encoding = locale.getpreferredencoding() 10 | _fallback_encodings = ['utf-8', 'cp1252'] 11 | 12 | 13 | def _try_decode(byte_string): 14 | """ 15 | Tries decoding a byte string from the OS into a unicode string 16 | 17 | :param byte_string: 18 | A byte string 19 | 20 | :return: 21 | A unicode string 22 | """ 23 | 24 | try: 25 | return str_cls(byte_string, _encoding) 26 | 27 | # If the "correct" encoding did not work, try some defaults, and then just 28 | # obliterate characters that we can't seen to decode properly 29 | except (UnicodeDecodeError): 30 | for encoding in _fallback_encodings: 31 | try: 32 | return str_cls(byte_string, encoding, errors='strict') 33 | except (UnicodeDecodeError): 34 | pass 35 | 36 | return str_cls(byte_string, errors='replace') 37 | -------------------------------------------------------------------------------- /package_control/commands/list_unmanaged_packages_command.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | 3 | from ..settings import load_list_setting, pc_settings_filename 4 | from .list_packages_command import ListPackagesCommand 5 | 6 | 7 | class ListUnmanagedPackagesCommand(ListPackagesCommand): 8 | 9 | """ 10 | A command that shows a list of all packages that are not managed by 11 | Package Control, i.e. that are installed, but not mentioned in 12 | `installed_packages`. 13 | """ 14 | 15 | def list_packages(self, manager): 16 | """ 17 | Build a list of packages to display. 18 | 19 | :param manager: 20 | The package manager instance to use. 21 | 22 | :returns: 23 | A list of package names to add to the quick panel 24 | """ 25 | 26 | settings = sublime.load_settings(pc_settings_filename()) 27 | ignored_packages = load_list_setting(settings, 'unmanaged_packages_ignore') 28 | ignored_packages |= load_list_setting(settings, 'installed_packages') 29 | 30 | packages = manager.list_packages() - ignored_packages 31 | return sorted(packages, key=lambda s: s.lower()) 32 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_win/_kernel32_cffi.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .._ffi import register_ffi 5 | from .._types import str_cls 6 | from ..errors import LibraryNotFoundError 7 | 8 | import cffi 9 | 10 | 11 | __all__ = [ 12 | 'get_error', 13 | 'kernel32', 14 | ] 15 | 16 | 17 | ffi = cffi.FFI() 18 | if cffi.__version_info__ >= (0, 9): 19 | ffi.set_unicode(True) 20 | ffi.cdef(""" 21 | typedef long long LARGE_INTEGER; 22 | BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount); 23 | 24 | typedef struct _FILETIME { 25 | DWORD dwLowDateTime; 26 | DWORD dwHighDateTime; 27 | } FILETIME; 28 | 29 | void GetSystemTimeAsFileTime(FILETIME *lpSystemTimeAsFileTime); 30 | """) 31 | 32 | 33 | try: 34 | kernel32 = ffi.dlopen('kernel32.dll') 35 | register_ffi(kernel32, ffi) 36 | 37 | except (OSError) as e: 38 | if str_cls(e).find('cannot load library') != -1: 39 | raise LibraryNotFoundError('kernel32.dll could not be found') 40 | raise 41 | 42 | 43 | def get_error(): 44 | return ffi.getwinerror() 45 | -------------------------------------------------------------------------------- /package_control/deps/asn1crypto/_types.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import inspect 5 | import sys 6 | 7 | 8 | if sys.version_info < (3,): 9 | str_cls = unicode # noqa 10 | byte_cls = str 11 | int_types = (int, long) # noqa 12 | 13 | def bytes_to_list(byte_string): 14 | return [ord(b) for b in byte_string] 15 | 16 | chr_cls = chr 17 | 18 | else: 19 | str_cls = str 20 | byte_cls = bytes 21 | int_types = int 22 | 23 | bytes_to_list = list 24 | 25 | def chr_cls(num): 26 | return bytes([num]) 27 | 28 | 29 | def type_name(value): 30 | """ 31 | Returns a user-readable name for the type of an object 32 | 33 | :param value: 34 | A value to get the type name of 35 | 36 | :return: 37 | A unicode string of the object's type name 38 | """ 39 | 40 | if inspect.isclass(value): 41 | cls = value 42 | else: 43 | cls = value.__class__ 44 | if cls.__module__ in set(['builtins', '__builtin__']): 45 | return cls.__name__ 46 | return '%s.%s' % (cls.__module__, cls.__name__) 47 | -------------------------------------------------------------------------------- /package_control/deps/__init__.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | import sys 3 | 4 | try: 5 | from .oscrypto import use_ctypes, use_openssl 6 | 7 | use_ctypes() 8 | 9 | # On Linux we need to use the version of OpenSSL included with Sublime Text 10 | # to prevent conflicts between two different versions of OpenSSL being 11 | # dynamically linked. On ST3, we can't use oscrypto for OpenSSL stuff since 12 | # it has OpenSSL statically linked, and we can't dlopen() that. 13 | # ST 4081 broke sys.executable to return "sublime_text", but other 4xxx builds 14 | # will contain "plugin_host". 15 | if sys.version_info[:2] == (3, 8) and sys.platform == 'linux' and ( 16 | 'sublime_text' in sys.executable or 17 | 'plugin_host' in sys.executable): 18 | install_dir = os.path.dirname(sys.executable) 19 | try: 20 | use_openssl( 21 | os.path.join(install_dir, 'libcrypto.so.1.1'), 22 | os.path.join(install_dir, 'libssl.so.1.1') 23 | ) 24 | except RuntimeError: 25 | pass # runtime error may be raised, when reloading modules. 26 | 27 | except ImportError: 28 | pass 29 | -------------------------------------------------------------------------------- /package_control/providers/schema_version.py: -------------------------------------------------------------------------------- 1 | from ..pep440 import PEP440Version 2 | 3 | 4 | class SchemaVersion(PEP440Version): 5 | supported_versions = ('2.0', '3.0.0', '4.0.0') 6 | 7 | def __init__(self, ver): 8 | """ 9 | Custom version string parsing to maintain backward compatibility. 10 | 11 | SemVer needs all of major, minor and patch parts being present in `ver`. 12 | 13 | :param ver: 14 | An integer, float or string containing a version string. 15 | 16 | :returns: 17 | List of (major, minor, patch) 18 | """ 19 | try: 20 | if isinstance(ver, int): 21 | ver = float(ver) 22 | if isinstance(ver, float): 23 | ver = str(ver) 24 | except ValueError: 25 | raise ValueError('the "schema_version" is not a valid number.') 26 | 27 | if ver not in self.supported_versions: 28 | raise ValueError( 29 | 'the "schema_version" is not recognized. Must be one of: %s or %s.' 30 | % (', '.join(self.supported_versions[:-1]), self.supported_versions[-1]) 31 | ) 32 | 33 | super().__init__(ver) 34 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_rand.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import os 5 | 6 | from ._errors import pretty_message 7 | from ._types import type_name, int_types 8 | 9 | 10 | __all__ = [ 11 | 'rand_bytes', 12 | ] 13 | 14 | 15 | def rand_bytes(length): 16 | """ 17 | Returns a number of random bytes suitable for cryptographic purposes 18 | 19 | :param length: 20 | The desired number of bytes 21 | 22 | :raises: 23 | ValueError - when any of the parameters contain an invalid value 24 | TypeError - when any of the parameters are of the wrong type 25 | OSError - when an error is returned by OpenSSL 26 | 27 | :return: 28 | A byte string 29 | """ 30 | 31 | if not isinstance(length, int_types): 32 | raise TypeError(pretty_message( 33 | ''' 34 | length must be an integer, not %s 35 | ''', 36 | type_name(length) 37 | )) 38 | 39 | if length < 1: 40 | raise ValueError('length must be greater than 0') 41 | 42 | if length > 1024: 43 | raise ValueError('length must not be greater than 1024') 44 | 45 | return os.urandom(length) 46 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_errors.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | Helper for formatting exception messages. Exports the following items: 5 | 6 | - pretty_message() 7 | """ 8 | 9 | from __future__ import unicode_literals, division, absolute_import, print_function 10 | 11 | import re 12 | import textwrap 13 | 14 | 15 | __all__ = [ 16 | 'pretty_message', 17 | ] 18 | 19 | 20 | def pretty_message(string, *params): 21 | """ 22 | Takes a multi-line string and does the following: 23 | 24 | - dedents 25 | - converts newlines with text before and after into a single line 26 | - strips leading and trailing whitespace 27 | 28 | :param string: 29 | The string to format 30 | 31 | :param *params: 32 | Params to interpolate into the string 33 | 34 | :return: 35 | The formatted string 36 | """ 37 | 38 | output = textwrap.dedent(string) 39 | 40 | # Unwrap lines, taking into account bulleted lists, ordered lists and 41 | # underlines consisting of = signs 42 | if output.find('\n') != -1: 43 | output = re.sub('(?<=\\S)\n(?=[^ \n\t\\d\\*\\-=])', ' ', output) 44 | 45 | if params: 46 | output = output % params 47 | 48 | output = output.strip() 49 | 50 | return output 51 | -------------------------------------------------------------------------------- /package_control/deps/asn1crypto/_errors.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | Exports the following items: 5 | 6 | - unwrap() 7 | - APIException() 8 | """ 9 | 10 | from __future__ import unicode_literals, division, absolute_import, print_function 11 | 12 | import re 13 | import textwrap 14 | 15 | 16 | class APIException(Exception): 17 | """ 18 | An exception indicating an API has been removed from asn1crypto 19 | """ 20 | 21 | pass 22 | 23 | 24 | def unwrap(string, *params): 25 | """ 26 | Takes a multi-line string and does the following: 27 | 28 | - dedents 29 | - converts newlines with text before and after into a single line 30 | - strips leading and trailing whitespace 31 | 32 | :param string: 33 | The string to format 34 | 35 | :param *params: 36 | Params to interpolate into the string 37 | 38 | :return: 39 | The formatted string 40 | """ 41 | 42 | output = textwrap.dedent(string) 43 | 44 | # Unwrap lines, taking into account bulleted lists, ordered lists and 45 | # underlines consisting of = signs 46 | if output.find('\n') != -1: 47 | output = re.sub('(?<=\\S)\n(?=[^ \n\t\\d\\*\\-=])', ' ', output) 48 | 49 | if params: 50 | output = output % params 51 | 52 | output = output.strip() 53 | 54 | return output 55 | -------------------------------------------------------------------------------- /package_control/deps/asn1crypto/__init__.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .version import __version__, __version_info__ 5 | 6 | __all__ = [ 7 | '__version__', 8 | '__version_info__', 9 | 'load_order', 10 | ] 11 | 12 | 13 | def load_order(): 14 | """ 15 | Returns a list of the module and sub-module names for asn1crypto in 16 | dependency load order, for the sake of live reloading code 17 | 18 | :return: 19 | A list of unicode strings of module names, as they would appear in 20 | sys.modules, ordered by which module should be reloaded first 21 | """ 22 | 23 | return [ 24 | 'asn1crypto._errors', 25 | 'asn1crypto._int', 26 | 'asn1crypto._ordereddict', 27 | 'asn1crypto._teletex_codec', 28 | 'asn1crypto._types', 29 | 'asn1crypto._inet', 30 | 'asn1crypto._iri', 31 | 'asn1crypto.version', 32 | 'asn1crypto.pem', 33 | 'asn1crypto.util', 34 | 'asn1crypto.parser', 35 | 'asn1crypto.core', 36 | 'asn1crypto.algos', 37 | 'asn1crypto.keys', 38 | 'asn1crypto.x509', 39 | 'asn1crypto.crl', 40 | 'asn1crypto.csr', 41 | 'asn1crypto.ocsp', 42 | 'asn1crypto.cms', 43 | 'asn1crypto.pdf', 44 | 'asn1crypto.pkcs12', 45 | 'asn1crypto.tsp', 46 | 'asn1crypto', 47 | ] 48 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_win/_kernel32_ctypes.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import ctypes 5 | from ctypes import windll, wintypes, POINTER, c_longlong, Structure 6 | 7 | from .._ffi import FFIEngineError 8 | from .._types import str_cls 9 | from ..errors import LibraryNotFoundError 10 | 11 | 12 | __all__ = [ 13 | 'get_error', 14 | 'kernel32', 15 | ] 16 | 17 | 18 | try: 19 | kernel32 = windll.kernel32 20 | except (OSError) as e: 21 | if str_cls(e).find('The specified module could not be found') != -1: 22 | raise LibraryNotFoundError('kernel32.dll could not be found') 23 | raise 24 | 25 | LARGE_INTEGER = c_longlong 26 | 27 | try: 28 | kernel32.QueryPerformanceCounter.argtypes = [POINTER(LARGE_INTEGER)] 29 | kernel32.QueryPerformanceCounter.restype = wintypes.BOOL 30 | 31 | class FILETIME(Structure): 32 | _fields_ = [ 33 | ("dwLowDateTime", wintypes.DWORD), 34 | ("dwHighDateTime", wintypes.DWORD), 35 | ] 36 | 37 | kernel32.GetSystemTimeAsFileTime.argtypes = [POINTER(FILETIME)] 38 | kernel32.GetSystemTimeAsFileTime.restype = None 39 | 40 | except (AttributeError): 41 | raise FFIEngineError('Error initializing ctypes') 42 | 43 | 44 | setattr(kernel32, 'LARGE_INTEGER', LARGE_INTEGER) 45 | setattr(kernel32, 'FILETIME', FILETIME) 46 | 47 | 48 | def get_error(): 49 | error = ctypes.GetLastError() 50 | return (error, ctypes.FormatError(error)) 51 | -------------------------------------------------------------------------------- /package_control/show_error.py: -------------------------------------------------------------------------------- 1 | import functools 2 | import sublime 3 | 4 | from . import text 5 | 6 | 7 | def show_error(string, params=None, strip=True, indent=None): 8 | """ 9 | Displays an error message with a standard "Package Control" header after 10 | running the string through text.format() 11 | 12 | :param string: 13 | The error to display 14 | 15 | :param params: 16 | Params to interpolate into the string 17 | 18 | :param strip: 19 | If the last newline in the string should be removed 20 | 21 | :param indent: 22 | If all lines should be indented by a set indent after being de-dented 23 | """ 24 | 25 | string = text.format(string, params, strip=strip, indent=indent) 26 | sublime.set_timeout(functools.partial(sublime.error_message, 'Package Control\n\n' + string), 50) 27 | 28 | 29 | def show_message(string, params=None, strip=True, indent=None): 30 | """ 31 | Displays an info message with a standard "Package Control" header after 32 | running the string through text.format() 33 | 34 | :param string: 35 | The error to display 36 | 37 | :param params: 38 | Params to interpolate into the string 39 | 40 | :param strip: 41 | If the last newline in the string should be removed 42 | 43 | :param indent: 44 | If all lines should be indented by a set indent after being de-dented 45 | """ 46 | 47 | string = text.format(string, params, strip=strip, indent=indent) 48 | sublime.set_timeout(functools.partial(sublime.message_dialog, 'Package Control\n\n' + string), 50) 49 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/util.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import sys 5 | 6 | from ._errors import pretty_message 7 | from ._types import type_name, byte_cls 8 | 9 | if sys.platform == 'darwin': 10 | from ._mac.util import rand_bytes 11 | elif sys.platform == 'win32': 12 | from ._win.util import rand_bytes 13 | else: 14 | from ._openssl.util import rand_bytes 15 | 16 | 17 | __all__ = [ 18 | 'constant_compare', 19 | 'rand_bytes', 20 | ] 21 | 22 | 23 | def constant_compare(a, b): 24 | """ 25 | Compares two byte strings in constant time to see if they are equal 26 | 27 | :param a: 28 | The first byte string 29 | 30 | :param b: 31 | The second byte string 32 | 33 | :return: 34 | A boolean if the two byte strings are equal 35 | """ 36 | 37 | if not isinstance(a, byte_cls): 38 | raise TypeError(pretty_message( 39 | ''' 40 | a must be a byte string, not %s 41 | ''', 42 | type_name(a) 43 | )) 44 | 45 | if not isinstance(b, byte_cls): 46 | raise TypeError(pretty_message( 47 | ''' 48 | b must be a byte string, not %s 49 | ''', 50 | type_name(b) 51 | )) 52 | 53 | if len(a) != len(b): 54 | return False 55 | 56 | if sys.version_info < (3,): 57 | a = [ord(char) for char in a] 58 | b = [ord(char) for char in b] 59 | 60 | result = 0 61 | for x, y in zip(a, b): 62 | result |= x ^ y 63 | return result == 0 64 | -------------------------------------------------------------------------------- /package_control/http/validating_https_handler.py: -------------------------------------------------------------------------------- 1 | import ssl 2 | from urllib.error import URLError 3 | import urllib.request as urllib_compat 4 | 5 | from .validating_https_connection import ValidatingHTTPSConnection 6 | from .invalid_certificate_exception import InvalidCertificateException 7 | from .persistent_handler import PersistentHandler 8 | 9 | 10 | class ValidatingHTTPSHandler(PersistentHandler, urllib_compat.HTTPSHandler): 11 | 12 | """ 13 | A urllib handler that validates SSL certificates for HTTPS requests 14 | """ 15 | 16 | def __init__(self, **kwargs): 17 | # This is a special value that will not trigger the standard debug 18 | # functionality, but custom code where we can format the output 19 | self._debuglevel = 0 20 | if 'debug' in kwargs and kwargs['debug']: 21 | self._debuglevel = 5 22 | elif 'debuglevel' in kwargs: 23 | self._debuglevel = kwargs['debuglevel'] 24 | self._connection_args = kwargs 25 | 26 | def https_open(self, req): 27 | def http_class_wrapper(host, **kwargs): 28 | full_kwargs = dict(self._connection_args) 29 | full_kwargs.update(kwargs) 30 | return ValidatingHTTPSConnection(host, **full_kwargs) 31 | 32 | try: 33 | return self.do_open(http_class_wrapper, req) 34 | except URLError as e: 35 | if type(e.reason) == ssl.SSLError and e.reason.args[0] == 1: 36 | raise InvalidCertificateException(req.host, '', 37 | e.reason.args[1]) 38 | raise 39 | 40 | https_request = urllib_compat.AbstractHTTPHandler.do_request_ 41 | -------------------------------------------------------------------------------- /messages/4.2.0.txt: -------------------------------------------------------------------------------- 1 | Version 4.2.0 Release Notes 2 | =========================== 3 | 4 | IMPORTANT NOTICE! 5 | 6 | This is the last version with support for ST3. 7 | 8 | NEW DEFAULT CHANNEL 9 | 10 | Package Control is using the following new default channel by default: 11 | 12 | https://packages.sublimetext.io/channel.json 13 | 14 | Any request to https://packagecontrol.io/channel_v3.json is redirected. 15 | 16 | To discover packages online, visit 17 | 18 | https://packages.sublimetext.io 19 | 20 | New packages and libraries are published daily at 0:00 UTC. 21 | 22 | Dedicated libraries channel is still available, but its content is merged 23 | into new default channel and thus doesn't need to be specified explicitly. 24 | 25 | This change is required as packagecontrol.io is more or less unmaintained 26 | for several years, didn't even receive related Package Control 4 updates, 27 | suffered various even long lasting outages and its infrastructure seems to 28 | struggle with current amount of packages and data needed to be managed, 29 | which results in packages frequently not being available for install or 30 | upgrade. As current community doesn't have access to its infrastructure. 31 | 32 | The new crawler works way more efficient and uses a more intelligent 33 | caching strategy to reduce network bandwidth. Full downloads are only 34 | made if packages or libraries have been added or modified really changed. 35 | 36 | There's still some work to do to consolidate new infrastructure, 37 | which this change is a first and important step, for. 38 | 39 | The new crawler and website are maintained under: 40 | 41 | https://github.com/packagecontrol 42 | -------------------------------------------------------------------------------- /package_control/commands/remove_packages_command.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | import sublime 4 | import sublime_plugin 5 | 6 | from ..activity_indicator import ActivityIndicator 7 | from ..package_tasks import PackageTaskRunner 8 | from ..show_error import show_error 9 | 10 | 11 | class RemovePackagesCommand(sublime_plugin.ApplicationCommand): 12 | 13 | """ 14 | A command that accepts a list of packages to remove, 15 | or prompts the user to paste a comma-separated list. 16 | 17 | Example: 18 | 19 | ```py 20 | sublime.run_command("remove_packages", {"packages": ["Package 1", "Package 2"]}) 21 | ``` 22 | """ 23 | 24 | def run(self, packages=None): 25 | if isinstance(packages, list): 26 | 27 | def worker(): 28 | with ActivityIndicator() as progress: 29 | remover = PackageTaskRunner() 30 | remover.remove_packages(packages, progress) 31 | 32 | threading.Thread(target=worker).start() 33 | return 34 | 35 | def on_done(input_text): 36 | packages = [] 37 | for package in input_text.split(','): 38 | if package: 39 | package = package.strip() 40 | if package: 41 | packages.append(package) 42 | 43 | if not packages: 44 | show_error('No package names were entered') 45 | return 46 | 47 | self.run(packages) 48 | 49 | sublime.active_window().show_input_panel( 50 | 'Packages to remove (comma-separated)', 51 | '', 52 | on_done, 53 | None, 54 | None 55 | ) 56 | -------------------------------------------------------------------------------- /package_control/commands/new_template_command.py: -------------------------------------------------------------------------------- 1 | import os 2 | import textwrap 3 | 4 | import sublime 5 | import sublime_plugin 6 | 7 | 8 | def reformat(template): 9 | return textwrap.dedent(template).lstrip() 10 | 11 | 12 | class NewChannelJsonCommand(sublime_plugin.WindowCommand): 13 | def run(self): 14 | view = self.window.new_file() 15 | view.settings().set("default_dir", os.path.join(sublime.packages_path(), "User")) 16 | view.assign_syntax("JSON.sublime-syntax") 17 | view.set_name("channel.json") 18 | 19 | template = reformat( 20 | """ 21 | { 22 | \t"\\$schema": "sublime://packagecontrol.io/schemas/channel", 23 | \t"schema_version": "4.0.0", 24 | \t"repositories": [ 25 | \t\t"$0" 26 | \t] 27 | } 28 | """ 29 | ) 30 | view.run_command("insert_snippet", {"contents": template}) 31 | 32 | 33 | class NewRepositoryJsonCommand(sublime_plugin.WindowCommand): 34 | def run(self): 35 | view = self.window.new_file() 36 | view.settings().set("default_dir", os.path.join(sublime.packages_path(), "User")) 37 | view.assign_syntax("JSON.sublime-syntax") 38 | view.set_name("repository.json") 39 | 40 | template = reformat( 41 | """ 42 | { 43 | \t"\\$schema": "sublime://packagecontrol.io/schemas/repository", 44 | \t"schema_version": "4.0.0", 45 | \t"packages": [ 46 | \t\t$0 47 | \t], 48 | \t"libraries": [] 49 | } 50 | """ 51 | ) 52 | view.run_command("insert_snippet", {"contents": template}) 53 | -------------------------------------------------------------------------------- /package_control/downloaders/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from ..console_write import console_write 4 | 5 | from .urllib_downloader import UrlLibDownloader 6 | from .curl_downloader import CurlDownloader 7 | from .wget_downloader import WgetDownloader 8 | 9 | DOWNLOADERS = { 10 | 'oscrypto': None, 11 | 'urllib': UrlLibDownloader, 12 | 'curl': CurlDownloader, 13 | 'wget': WgetDownloader 14 | } 15 | 16 | # oscrypto can fail badly 17 | # 1. on Linux in the Sublime Text 3 environment due to trying to mix the 18 | # statically-linked OpenSSL in plugin_host with the OpenSSL loaded from the 19 | # operating system. On Python 3.8 we dynamically link OpenSSL, so it just needs 20 | # to be configured properly, which is handled in oscrypto_downloader.py. 21 | # 2. on MacOS ARM plattform due to whatever reason. Due to maintanance state of 22 | # oscrypto, start fading it out by disabling it on python 3.8 (ST4) 23 | if sys.platform != 'linux' and sys.version_info[:2] == (3, 3): 24 | try: 25 | from .oscrypto_downloader import OscryptoDownloader 26 | DOWNLOADERS['oscrypto'] = OscryptoDownloader 27 | except Exception as e: 28 | console_write( 29 | ''' 30 | OscryptoDownloader not available! %s 31 | ''', 32 | str(e) 33 | ) 34 | 35 | if sys.platform == 'win32': 36 | try: 37 | from .wininet_downloader import WinINetDownloader 38 | DOWNLOADERS['wininet'] = WinINetDownloader 39 | except Exception as e: 40 | DOWNLOADERS['wininet'] = None 41 | console_write( 42 | ''' 43 | WinINetDownloader not available! %s 44 | ''', 45 | str(e) 46 | ) 47 | -------------------------------------------------------------------------------- /package_control/commands/clear_package_cache_command.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | from ..clear_directory import clear_directory 5 | from ..console_write import console_write 6 | from ..show_error import show_message 7 | from ..sys_path import cache_path, shortpath 8 | 9 | 10 | class ClearPackageCacheCommand(sublime_plugin.ApplicationCommand): 11 | 12 | """ 13 | A command that clears out ST's Cache directory. 14 | 15 | Example: 16 | 17 | ```py 18 | sublime.run_command( 19 | "clear_package_cache", 20 | { 21 | "unattended": False # if True, suppress error dialogs 22 | } 23 | ) 24 | ``` 25 | """ 26 | 27 | def run(self, unattended=False): 28 | folder = cache_path() 29 | 30 | if not unattended: 31 | msg = 'Do you want to clear "{}" to reset all packages to freshly installed state?'.format( 32 | shortpath(folder) 33 | ) 34 | 35 | # ST4 supports modal dialogs with title 36 | if hasattr(sublime.ok_cancel_dialog, "title") and not sublime.ok_cancel_dialog( 37 | msg, title="Clear Sublime Text Cache Directory?" 38 | ): 39 | return 40 | 41 | # ST3 42 | elif not sublime.ok_cancel_dialog(msg): 43 | return 44 | 45 | if not clear_directory(folder, ignore_errors=False): 46 | return 47 | 48 | msg = "Sublime Text's cache directory has been cleared!" 49 | console_write(msg) 50 | 51 | if unattended: 52 | return 53 | 54 | msg += "\n\nYou might need to restart Sublime Text for changes to take effect." 55 | show_message(msg) 56 | -------------------------------------------------------------------------------- /package_control/commands/remove_repository_command.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | from ..settings import pc_settings_filename 5 | from ..show_error import show_message 6 | 7 | 8 | class RemoveRepositoryCommand(sublime_plugin.ApplicationCommand): 9 | 10 | """ 11 | A command to remove a repository from the user's Package Control settings 12 | 13 | Example: 14 | 15 | ```py 16 | sublime.run_command( 17 | "remove_repository", 18 | { 19 | "url": "https://my-server.com/repository.json", 20 | "unattended": False # if True, suppress error dialogs 21 | } 22 | ) 23 | ``` 24 | """ 25 | 26 | def run(self, url=None, unattended=False): 27 | settings = sublime.load_settings(pc_settings_filename()) 28 | repositories = settings.get('repositories') 29 | if not repositories: 30 | if not url or not unattended: 31 | show_message('There are no repositories to remove') 32 | return 33 | 34 | if url: 35 | try: 36 | repositories.remove(url) 37 | except (ValueError): 38 | pass 39 | else: 40 | settings.set('repositories', repositories) 41 | sublime.save_settings(pc_settings_filename()) 42 | sublime.status_message('Repository %s successfully removed' % url) 43 | return 44 | 45 | def on_done(index): 46 | if index == -1: 47 | return 48 | 49 | self.run(repositories[index]) 50 | 51 | sublime.active_window().show_quick_panel( 52 | repositories, 53 | on_done, 54 | sublime.KEEP_OPEN_ON_FOCUS_LOST 55 | ) 56 | -------------------------------------------------------------------------------- /package_control/commands/enable_package_command.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | 3 | from ..package_disabler import PackageDisabler 4 | from .existing_packages_command import ExistingPackagesCommand 5 | 6 | 7 | class EnablePackageCommand(ExistingPackagesCommand): 8 | 9 | """ 10 | A command that removes a package from Sublime Text's ignored packages list 11 | """ 12 | 13 | def action(self): 14 | """ 15 | Build a strng to describe the action taken on selected package. 16 | """ 17 | 18 | return "enable" 19 | 20 | def no_packages_error(self): 21 | """ 22 | Return the error message to display if no packages are availablw. 23 | """ 24 | 25 | return "There are no disabled packages to enable" 26 | 27 | def list_packages(self, manager): 28 | """ 29 | Build a list of packages to display. 30 | 31 | :param manager: 32 | The package manager instance to use. 33 | 34 | :returns: 35 | A list of package names to add to the quick panel 36 | """ 37 | 38 | return sorted( 39 | filter(lambda p: manager.is_compatible(p), PackageDisabler.ignored_packages()), 40 | key=lambda s: s.lower() 41 | ) 42 | 43 | def on_done(self, manager, package_name): 44 | """ 45 | Quick panel user selection handler - enables the selected package 46 | 47 | :param manager: 48 | The package manager instance to use. 49 | 50 | :param package_name: 51 | A package name to perform action for 52 | """ 53 | 54 | PackageDisabler.reenable_packages({PackageDisabler.ENABLE: package_name}) 55 | 56 | sublime.status_message('Package %s successfully enabled.' % package_name) 57 | -------------------------------------------------------------------------------- /package_control/downloaders/decoding_downloader.py: -------------------------------------------------------------------------------- 1 | import gzip 2 | import zlib 3 | from io import BytesIO 4 | 5 | try: 6 | import bz2 7 | except (ImportError): 8 | bz2 = None 9 | 10 | from .downloader_exception import DownloaderException 11 | 12 | 13 | class DecodingDownloader: 14 | 15 | """ 16 | A base for downloaders that provides the ability to decode bzip2ed, gzipped 17 | or deflated content. 18 | """ 19 | 20 | def supported_encodings(self): 21 | """ 22 | Determines the supported encodings we can decode 23 | 24 | :return: 25 | A comma-separated string of valid encodings 26 | """ 27 | 28 | encodings = 'gzip,deflate' 29 | if bz2: 30 | encodings = 'bzip2,' + encodings 31 | return encodings 32 | 33 | def decode_response(self, encoding, response): 34 | """ 35 | Decodes the raw response from the web server based on the 36 | Content-Encoding HTTP header 37 | 38 | :param encoding: 39 | The value of the Content-Encoding HTTP header 40 | 41 | :param response: 42 | The raw response from the server 43 | 44 | :return: 45 | The decoded response 46 | """ 47 | 48 | if encoding == 'bzip2': 49 | if bz2: 50 | return bz2.decompress(response) 51 | else: 52 | raise DownloaderException('Received bzip2 file contents, but was unable to import the bz2 module') 53 | elif encoding == 'gzip': 54 | return gzip.GzipFile(fileobj=BytesIO(response)).read() 55 | elif encoding == 'deflate': 56 | decompresser = zlib.decompressobj(-zlib.MAX_WBITS) 57 | return decompresser.decompress(response) + decompresser.flush() 58 | return response 59 | -------------------------------------------------------------------------------- /package_control/commands/disable_package_command.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | 3 | from ..package_disabler import PackageDisabler 4 | from .existing_packages_command import ExistingPackagesCommand 5 | 6 | 7 | class DisablePackageCommand(ExistingPackagesCommand): 8 | 9 | """ 10 | A command that adds a package to Sublime Text's ignored packages list 11 | """ 12 | 13 | def action(self): 14 | """ 15 | Build a strng to describe the action taken on selected package. 16 | """ 17 | 18 | return "disable" 19 | 20 | def no_packages_error(self): 21 | """ 22 | Return the error message to display if no packages are availablw. 23 | """ 24 | 25 | return "There are no enabled packages to disable" 26 | 27 | def list_packages(self, manager): 28 | """ 29 | Build a list of packages to display. 30 | 31 | :param manager: 32 | The package manager instance to use. 33 | 34 | :returns: 35 | A list of package names to add to the quick panel 36 | """ 37 | 38 | return sorted( 39 | manager.list_all_packages() 40 | - PackageDisabler.ignored_packages() 41 | - {'Binary', 'Default', 'Package Control', 'Text'}, 42 | key=lambda s: s.lower() 43 | ) 44 | 45 | def on_done(self, manager, package_name): 46 | """ 47 | Quick panel user selection handler - disables the selected package 48 | 49 | :param manager: 50 | The package manager instance to use. 51 | 52 | :param package_name: 53 | A package name to perform action for 54 | """ 55 | 56 | PackageDisabler.disable_packages({PackageDisabler.DISABLE: package_name}) 57 | 58 | sublime.status_message('Package %s successfully disabled.' % package_name) 59 | -------------------------------------------------------------------------------- /package_control/commands/enable_packages_command.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | from ..package_disabler import PackageDisabler 5 | from ..package_manager import PackageManager 6 | from ..show_error import show_error 7 | 8 | 9 | class EnablePackagesCommand(sublime_plugin.ApplicationCommand): 10 | 11 | """ 12 | A command that accepts a list of packages to enable, 13 | or prompts the user to paste a comma-separated list. 14 | 15 | Example: 16 | 17 | ```py 18 | sublime.run_command("enable_packages", {"packages": ["Package 1", "Package 2"]}) 19 | ``` 20 | """ 21 | 22 | def run(self, packages=None): 23 | if isinstance(packages, list): 24 | manager = PackageManager() 25 | unique_packages = set(filter(lambda p: manager.is_compatible(p), packages)) 26 | 27 | PackageDisabler.reenable_packages({PackageDisabler.ENABLE: unique_packages}) 28 | 29 | if len(unique_packages) == 1: 30 | message = 'Package %s successfully enabled.' % packages[0] 31 | else: 32 | message = '%d packages have been enabled.' % len(unique_packages) 33 | 34 | sublime.status_message(message) 35 | return 36 | 37 | def on_done(input_text): 38 | packages = [] 39 | for package in input_text.split(','): 40 | if package: 41 | package = package.strip() 42 | if package: 43 | packages.append(package) 44 | 45 | if not packages: 46 | show_error('No package names were entered') 47 | return 48 | 49 | self.run(packages) 50 | 51 | sublime.active_window().show_input_panel( 52 | 'Packages to enable (comma-separated)', 53 | '', 54 | on_done, 55 | None, 56 | None 57 | ) 58 | -------------------------------------------------------------------------------- /package_control/commands/remove_package_command.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from ..activity_indicator import ActivityIndicator 4 | from ..package_tasks import PackageTaskRunner 5 | from .existing_packages_command import ExistingPackagesCommand 6 | 7 | 8 | class RemovePackageCommand(ExistingPackagesCommand): 9 | 10 | """ 11 | A command that presents a list of installed packages, allowing the user to 12 | select one to remove 13 | """ 14 | 15 | def action(self): 16 | """ 17 | Build a strng to describe the action taken on selected package. 18 | """ 19 | 20 | return "remove" 21 | 22 | def no_packages_error(self): 23 | """ 24 | Return the error message to display if no packages are availablw. 25 | """ 26 | 27 | return "There are no packages that can be removed" 28 | 29 | def list_packages(self, manager): 30 | """ 31 | Build a list of packages installed by user. 32 | 33 | :param manager: 34 | The package manager instance to use. 35 | 36 | :returns: 37 | A list of package names to add to the quick panel 38 | """ 39 | 40 | return ( 41 | manager.list_packages() 42 | - manager.list_default_packages() 43 | - manager.predefined_packages() 44 | ) 45 | 46 | def on_done(self, manager, package_name): 47 | """ 48 | Callback function to perform action on selected package. 49 | 50 | :param manager: 51 | The package manager instance to use. 52 | 53 | :param package_name: 54 | A package name to perform action for 55 | """ 56 | 57 | def worker(): 58 | with ActivityIndicator() as progress: 59 | remover = PackageTaskRunner(manager) 60 | remover.remove_packages({package_name}, progress) 61 | 62 | threading.Thread(target=worker).start() 63 | -------------------------------------------------------------------------------- /package_control/commands/satisfy_libraries_command.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | import sublime_plugin 4 | 5 | from ..activity_indicator import ActivityIndicator 6 | from ..console_write import console_write 7 | from ..package_manager import PackageManager 8 | from ..show_error import show_error 9 | 10 | 11 | class SatisfyLibrariesCommand(sublime_plugin.ApplicationCommand): 12 | 13 | """ 14 | A command that finds all libraries required by the installed packages 15 | and makes sure they are all installed and up-to-date. 16 | """ 17 | 18 | def run(self): 19 | 20 | def satisfy(): 21 | manager = PackageManager() 22 | 23 | with ActivityIndicator('Satisfying libraries...') as progress: 24 | error = False 25 | 26 | required_libraries = manager.find_required_libraries() 27 | 28 | if not manager.cleanup_libraries(required_libraries=required_libraries): 29 | show_error( 30 | ''' 31 | One or more orphaned libraries could not be removed. 32 | 33 | Please check the console for details. 34 | ''' 35 | ) 36 | error = True 37 | 38 | if not manager.install_libraries(libraries=required_libraries, fail_early=False): 39 | show_error( 40 | ''' 41 | One or more libraries could not be installed or updated. 42 | 43 | Please check the console for details. 44 | ''' 45 | ) 46 | error = True 47 | 48 | if not error: 49 | message = 'All libraries have been satisfied!' 50 | console_write(message) 51 | progress.finish(message) 52 | 53 | threading.Thread(target=satisfy).start() 54 | -------------------------------------------------------------------------------- /package_control/providers/provider_exception.py: -------------------------------------------------------------------------------- 1 | class ProviderException(Exception): 2 | 3 | """If a provider could not return information""" 4 | 5 | 6 | class GitProviderUserInfoException(ProviderException): 7 | """ 8 | Exception for signalling user information download error. 9 | 10 | The exception is used to indicate a given URL not being in expected form 11 | to be used by given provider to download user info from. 12 | """ 13 | 14 | def __init__(self, provider): 15 | self.provider_name = provider.__class__.__name__ 16 | self.url = provider.repo_url 17 | 18 | def __str__(self): 19 | return '%s unable to fetch user information from "%s".' % (self.provider_name, self.url) 20 | 21 | 22 | class GitProviderRepoInfoException(ProviderException): 23 | """ 24 | Exception for signalling repository information download error. 25 | 26 | The exception is used to indicate a given URL not being in expected form 27 | to be used by given provider to download repo info from. 28 | """ 29 | 30 | def __init__(self, provider): 31 | self.provider_name = provider.__class__.__name__ 32 | self.url = provider.repo_url 33 | 34 | def __str__(self): 35 | return '%s unable to fetch repo information from "%s".' % (self.provider_name, self.url) 36 | 37 | 38 | class GitProviderDownloadInfoException(ProviderException): 39 | """ 40 | Exception for signalling download information download error. 41 | 42 | The exception is used to indicate a given URL not being in expected form 43 | to be used by given provider to download release information from. 44 | """ 45 | 46 | def __init__(self, provider, url=None): 47 | self.provider_name = provider.__class__.__name__ 48 | self.url = url or provider.repo_url 49 | 50 | def __str__(self): 51 | return '%s unable to fetch download information from "%s".' % (self.provider_name, self.url) 52 | -------------------------------------------------------------------------------- /package_control/commands/revert_package_command.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | from ..activity_indicator import ActivityIndicator 4 | from ..package_tasks import PackageTaskRunner 5 | from .existing_packages_command import ExistingPackagesCommand 6 | 7 | 8 | class RevertPackageCommand(ExistingPackagesCommand): 9 | 10 | """ 11 | A command that presents a list of installed packages, allowing the user to 12 | select one to revert 13 | """ 14 | 15 | def action(self): 16 | """ 17 | Build a strng to describe the action taken on selected package. 18 | """ 19 | 20 | return "revert to" 21 | 22 | def no_packages_error(self): 23 | """ 24 | Return the error message to display if no packages are availablw. 25 | """ 26 | 27 | return "There are no built-in package overrides that can be reverted" 28 | 29 | def list_packages(self, manager): 30 | """ 31 | Build a list of packages installed by user. 32 | 33 | :param manager: 34 | The package manager instance to use. 35 | 36 | :returns: 37 | A list of package names to add to the quick panel 38 | """ 39 | 40 | return ( 41 | manager.list_packages() 42 | & manager.list_default_packages() 43 | - manager.predefined_packages() 44 | ) 45 | 46 | def on_done(self, manager, package_name): 47 | """ 48 | Callback function to perform action on selected package. 49 | 50 | :param manager: 51 | The package manager instance to use. 52 | 53 | :param package_name: 54 | A package name to perform action for 55 | """ 56 | 57 | def worker(): 58 | with ActivityIndicator() as progress: 59 | remover = PackageTaskRunner(manager) 60 | remover.remove_packages({package_name}, progress) 61 | 62 | threading.Thread(target=worker).start() 63 | -------------------------------------------------------------------------------- /package_control/commands/install_packages_command.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | import sublime 4 | import sublime_plugin 5 | 6 | from ..activity_indicator import ActivityIndicator 7 | from ..console_write import console_write 8 | from ..package_tasks import PackageTaskRunner 9 | from ..show_error import show_error 10 | 11 | 12 | class InstallPackagesCommand(sublime_plugin.ApplicationCommand): 13 | 14 | """ 15 | A command that accepts a list of packages to install, 16 | or prompts the user to paste a comma-separated list. 17 | 18 | Example: 19 | 20 | ```py 21 | sublime.run_command( 22 | "install_packages", 23 | { 24 | "packages": ["Package 1", "Package 2"], 25 | "unattended": False # if True, suppress error dialogs 26 | } 27 | ) 28 | ``` 29 | """ 30 | 31 | def run(self, packages=None, unattended=False): 32 | if isinstance(packages, list): 33 | 34 | def worker(): 35 | message = 'Loading packages...' 36 | with ActivityIndicator(message) as progress: 37 | console_write(message) 38 | installer = PackageTaskRunner() 39 | installer.install_packages(packages, unattended, progress) 40 | 41 | threading.Thread(target=worker).start() 42 | return 43 | 44 | def on_done(input_text): 45 | packages = [] 46 | for package in input_text.split(','): 47 | if package: 48 | package = package.strip() 49 | if package: 50 | packages.append(package) 51 | 52 | if not packages: 53 | show_error('No package names were entered') 54 | return 55 | 56 | self.run(packages, False) 57 | 58 | sublime.active_window().show_input_panel( 59 | 'Packages to install (comma-separated)', 60 | '', 61 | on_done, 62 | None, 63 | None 64 | ) 65 | -------------------------------------------------------------------------------- /package_control/commands/upgrade_packages_command.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | import sublime 4 | import sublime_plugin 5 | 6 | from ..activity_indicator import ActivityIndicator 7 | from ..console_write import console_write 8 | from ..package_tasks import PackageTaskRunner 9 | from ..show_error import show_error 10 | 11 | 12 | class UpgradePackagesCommand(sublime_plugin.ApplicationCommand): 13 | 14 | """ 15 | A command that accepts a list of packages to upgrade, 16 | or prompts the user to paste a comma-separated list. 17 | 18 | Example: 19 | 20 | ```py 21 | sublime.run_command( 22 | "upgrade_packages", 23 | { 24 | "packages": ["Package 1", "Package 2"], 25 | "unattended": False # if True, suppress error dialogs 26 | } 27 | ) 28 | ``` 29 | """ 30 | 31 | def run(self, packages=None, unattended=False): 32 | if isinstance(packages, list): 33 | 34 | def worker(): 35 | message = 'Searching updates...' 36 | with ActivityIndicator(message) as progress: 37 | console_write(message) 38 | upgrader = PackageTaskRunner() 39 | upgrader.upgrade_packages(packages, None, unattended, progress) 40 | 41 | threading.Thread(target=worker).start() 42 | return 43 | 44 | def on_done(input_text): 45 | packages = [] 46 | for package in input_text.split(','): 47 | if package: 48 | package = package.strip() 49 | if package: 50 | packages.append(package) 51 | 52 | if not packages: 53 | show_error('No package names were entered') 54 | return 55 | 56 | self.run(packages, False) 57 | 58 | sublime.active_window().show_input_panel( 59 | 'Packages to upgrade (comma-separated)', 60 | '', 61 | on_done, 62 | None, 63 | None 64 | ) 65 | -------------------------------------------------------------------------------- /package_control/commands/install_package_command.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | import sublime 4 | import sublime_plugin 5 | 6 | from ..activity_indicator import ActivityIndicator 7 | from ..console_write import console_write 8 | from ..package_tasks import PackageTaskRunner 9 | from ..show_error import show_message 10 | 11 | 12 | class InstallPackageCommand(sublime_plugin.ApplicationCommand): 13 | 14 | """ 15 | A command that presents the list of available packages and allows the 16 | user to pick one to install. 17 | """ 18 | 19 | def run(self): 20 | 21 | def show_quick_panel(): 22 | installer = PackageTaskRunner() 23 | 24 | with ActivityIndicator('Loading packages...') as progress: 25 | tasks = installer.create_package_tasks(actions=(installer.INSTALL, installer.OVERWRITE)) 26 | if not tasks: 27 | message = 'There are no packages available for installation' 28 | console_write(message) 29 | progress.finish(message) 30 | show_message( 31 | ''' 32 | %s 33 | 34 | Please see https://packagecontrol.io/docs/troubleshooting for help 35 | ''', 36 | message 37 | ) 38 | return 39 | 40 | def on_done(picked): 41 | if picked == -1: 42 | return 43 | 44 | def worker(task): 45 | with ActivityIndicator('Installing package %s' % task.package_name) as progress: 46 | installer.run_install_tasks([task], progress) 47 | 48 | threading.Thread(target=worker, args=[tasks[picked]]).start() 49 | 50 | sublime.active_window().show_quick_panel( 51 | installer.render_quick_panel_items(tasks), 52 | on_done, 53 | sublime.KEEP_OPEN_ON_FOCUS_LOST 54 | ) 55 | 56 | threading.Thread(target=show_quick_panel).start() 57 | -------------------------------------------------------------------------------- /package_control/commands/disable_packages_command.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | from ..package_disabler import PackageDisabler 5 | from ..show_error import show_error 6 | 7 | 8 | class DisablePackagesCommand(sublime_plugin.ApplicationCommand): 9 | 10 | """ 11 | A command that accepts a list of packages to disable, 12 | or prompts the user to paste a comma-separated list. 13 | 14 | Example: 15 | 16 | ```py 17 | sublime.run_command("disable_packages", {"packages": ["Package 1", "Package 2"]}) 18 | ``` 19 | """ 20 | 21 | def run(self, packages=None): 22 | if isinstance(packages, list): 23 | unique_packages = set(packages) - {'Binary', 'Default', 'Package Control', 'Text', 'User'} 24 | 25 | disabled = PackageDisabler.disable_packages({PackageDisabler.DISABLE: unique_packages}) 26 | 27 | num_packages = len(unique_packages) 28 | num_disabled = len(disabled) 29 | 30 | if num_packages == num_disabled: 31 | if num_packages == 1: 32 | message = 'Package %s successfully disabled.' % packages[0] 33 | else: 34 | message = '%d packages have been disabled.' % num_disabled 35 | else: 36 | message = '%d of %d packages have been disabled.' % (num_disabled, num_packages) 37 | 38 | sublime.status_message(message) 39 | return 40 | 41 | def on_done(input_text): 42 | packages = [] 43 | for package in input_text.split(','): 44 | if package: 45 | package = package.strip() 46 | if package: 47 | packages.append(package) 48 | 49 | if not packages: 50 | show_error('No package names were entered') 51 | return 52 | 53 | self.run(packages) 54 | 55 | sublime.active_window().show_input_panel( 56 | 'Packages to disable (comma-separated)', 57 | '', 58 | on_done, 59 | None, 60 | None 61 | ) 62 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/symmetric.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from . import backend 5 | 6 | 7 | _backend = backend() 8 | 9 | 10 | if _backend == 'mac': 11 | from ._mac.symmetric import ( 12 | aes_cbc_no_padding_decrypt, 13 | aes_cbc_no_padding_encrypt, 14 | aes_cbc_pkcs7_decrypt, 15 | aes_cbc_pkcs7_encrypt, 16 | des_cbc_pkcs5_decrypt, 17 | des_cbc_pkcs5_encrypt, 18 | rc2_cbc_pkcs5_decrypt, 19 | rc2_cbc_pkcs5_encrypt, 20 | rc4_decrypt, 21 | rc4_encrypt, 22 | tripledes_cbc_pkcs5_decrypt, 23 | tripledes_cbc_pkcs5_encrypt, 24 | ) 25 | 26 | elif _backend == 'win' or _backend == 'winlegacy': 27 | from ._win.symmetric import ( 28 | aes_cbc_no_padding_decrypt, 29 | aes_cbc_no_padding_encrypt, 30 | aes_cbc_pkcs7_decrypt, 31 | aes_cbc_pkcs7_encrypt, 32 | des_cbc_pkcs5_decrypt, 33 | des_cbc_pkcs5_encrypt, 34 | rc2_cbc_pkcs5_decrypt, 35 | rc2_cbc_pkcs5_encrypt, 36 | rc4_decrypt, 37 | rc4_encrypt, 38 | tripledes_cbc_pkcs5_decrypt, 39 | tripledes_cbc_pkcs5_encrypt, 40 | ) 41 | 42 | else: 43 | from ._openssl.symmetric import ( 44 | aes_cbc_no_padding_decrypt, 45 | aes_cbc_no_padding_encrypt, 46 | aes_cbc_pkcs7_decrypt, 47 | aes_cbc_pkcs7_encrypt, 48 | des_cbc_pkcs5_decrypt, 49 | des_cbc_pkcs5_encrypt, 50 | rc2_cbc_pkcs5_decrypt, 51 | rc2_cbc_pkcs5_encrypt, 52 | rc4_decrypt, 53 | rc4_encrypt, 54 | tripledes_cbc_pkcs5_decrypt, 55 | tripledes_cbc_pkcs5_encrypt, 56 | ) 57 | 58 | 59 | __all__ = [ 60 | 'aes_cbc_no_padding_decrypt', 61 | 'aes_cbc_no_padding_encrypt', 62 | 'aes_cbc_pkcs7_decrypt', 63 | 'aes_cbc_pkcs7_encrypt', 64 | 'des_cbc_pkcs5_decrypt', 65 | 'des_cbc_pkcs5_encrypt', 66 | 'rc2_cbc_pkcs5_decrypt', 67 | 'rc2_cbc_pkcs5_encrypt', 68 | 'rc4_decrypt', 69 | 'rc4_encrypt', 70 | 'tripledes_cbc_pkcs5_decrypt', 71 | 'tripledes_cbc_pkcs5_encrypt', 72 | ] 73 | -------------------------------------------------------------------------------- /package_control/commands/remove_channel_command.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | import sublime_plugin 3 | 4 | from .. import text 5 | from ..settings import pc_settings_filename 6 | from ..show_error import show_message 7 | 8 | 9 | class RemoveChannelCommand(sublime_plugin.ApplicationCommand): 10 | 11 | """ 12 | A command to remove a channel from the user's Package Control settings 13 | 14 | Example: 15 | 16 | ```py 17 | sublime.run_command( 18 | "remove_channel", 19 | { 20 | "url": "https://my-server.com/channel.json", 21 | "unattended": False # if True, suppress error dialogs 22 | } 23 | ) 24 | ``` 25 | """ 26 | 27 | def run(self, url=None, unattended=False): 28 | settings = sublime.load_settings(pc_settings_filename()) 29 | channels = settings.get('channels') 30 | if not channels: 31 | if not url or not unattended: 32 | show_message('There are no channels to remove') 33 | return 34 | 35 | if url: 36 | try: 37 | channels.remove(url) 38 | except (ValueError): 39 | pass 40 | else: 41 | settings.set('channels', channels) 42 | sublime.save_settings(pc_settings_filename()) 43 | sublime.status_message('Channel %s successfully removed' % url) 44 | return 45 | 46 | if len(channels) == 1: 47 | message = text.format( 48 | ''' 49 | Package Control 50 | 51 | You are about to remove the only channel in your settings. This 52 | will mean you will no longer be able to install or update 53 | packages. 54 | ''' 55 | ) 56 | if not sublime.ok_cancel_dialog(message, 'Ok'): 57 | return 58 | 59 | def on_done(index): 60 | if index == -1: 61 | return 62 | 63 | self.run(channels[index]) 64 | 65 | sublime.active_window().show_quick_panel( 66 | channels, 67 | on_done, 68 | sublime.KEEP_OPEN_ON_FOCUS_LOST 69 | ) 70 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_win/_crypt32.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .. import ffi 5 | from ._decode import _try_decode 6 | from .._ffi import buffer_from_bytes 7 | from .._types import str_cls 8 | 9 | if ffi() == 'cffi': 10 | from ._crypt32_cffi import crypt32, get_error 11 | else: 12 | from ._crypt32_ctypes import crypt32, get_error 13 | 14 | 15 | __all__ = [ 16 | 'crypt32', 17 | 'Crypt32Const', 18 | 'handle_error', 19 | ] 20 | 21 | 22 | def handle_error(result): 23 | """ 24 | Extracts the last Windows error message into a python unicode string 25 | 26 | :param result: 27 | A function result, 0 or None indicates failure 28 | 29 | :return: 30 | A unicode string error message 31 | """ 32 | 33 | if result: 34 | return 35 | 36 | _, error_string = get_error() 37 | 38 | if not isinstance(error_string, str_cls): 39 | error_string = _try_decode(error_string) 40 | 41 | raise OSError(error_string) 42 | 43 | 44 | class Crypt32Const(): 45 | X509_ASN_ENCODING = 1 46 | 47 | ERROR_INSUFFICIENT_BUFFER = 122 48 | CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG = 0x4 49 | CRYPT_E_NOT_FOUND = -2146885628 50 | 51 | CERT_STORE_PROV_MEMORY = b'Memory' 52 | CERT_STORE_CREATE_NEW_FLAG = 0x00002000 53 | CERT_STORE_ADD_USE_EXISTING = 2 54 | USAGE_MATCH_TYPE_OR = 1 55 | CERT_CHAIN_POLICY_SSL = 4 56 | AUTHTYPE_SERVER = 2 57 | CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG = 0x00000010 58 | CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS = 0x00000F00 59 | CERT_CHAIN_CACHE_END_CERT = 1 60 | CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY = 0x80000000 61 | 62 | TRUST_E_CERT_SIGNATURE = 0x80096004 63 | 64 | CERT_E_EXPIRED = 0x800B0101 65 | CERT_E_ROLE = 0x800B0103 66 | CERT_E_PURPOSE = 0x800B0106 67 | CERT_E_UNTRUSTEDROOT = 0x800B0109 68 | CERT_E_CN_NO_MATCH = 0x800B010F 69 | CRYPT_E_REVOKED = 0x80092010 70 | 71 | PKIX_KP_SERVER_AUTH = buffer_from_bytes(b"1.3.6.1.5.5.7.3.1\x00") 72 | SERVER_GATED_CRYPTO = buffer_from_bytes(b"1.3.6.1.4.1.311.10.3.3\x00") 73 | SGC_NETSCAPE = buffer_from_bytes(b"2.16.840.1.113730.4.1\x00") 74 | -------------------------------------------------------------------------------- /package_control/commands/list_packages_command.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import sublime 4 | 5 | from .. import package_io 6 | from .. import sys_path 7 | from .existing_packages_command import ExistingPackagesCommand 8 | 9 | 10 | class ListPackagesCommand(ExistingPackagesCommand): 11 | 12 | """ 13 | A command that shows a list of all installed packages in the quick panel 14 | """ 15 | 16 | def action(self): 17 | """ 18 | Build a strng to describe the action taken on selected package. 19 | """ 20 | 21 | return "goto" 22 | 23 | def no_packages_error(self): 24 | """ 25 | Return the error message to display if no packages are availablw. 26 | """ 27 | 28 | return "There are no packages to list" 29 | 30 | def list_packages(self, manager): 31 | """ 32 | Build a list of packages to display. 33 | 34 | :param manager: 35 | The package manager instance to use. 36 | 37 | :returns: 38 | A list of package names to add to the quick panel 39 | """ 40 | 41 | return sorted(manager.list_packages(), key=lambda s: s.lower()) 42 | 43 | def on_done(self, manager, package_name): 44 | """ 45 | Quick panel user selection handler - opens the homepage for any 46 | selected package in the user's browser 47 | 48 | :param manager: 49 | The package manager instance to use. 50 | 51 | :param package_name: 52 | A package name to perform action for 53 | """ 54 | 55 | package_dir = package_io.get_package_dir(package_name) 56 | package_file = None 57 | 58 | if not os.path.exists(package_dir): 59 | package_path = package_io.get_installed_package_path(package_name) 60 | if os.path.exists(package_path): 61 | package_dir, package_file = os.path.split(package_path) 62 | else: 63 | package_dir = os.path.dirname(package_path) 64 | 65 | open_dir_file = {'dir': sys_path.shortpath(package_dir)} 66 | if package_file is not None: 67 | open_dir_file['file'] = package_file 68 | 69 | sublime.active_window().run_command('open_dir', open_dir_file) 70 | -------------------------------------------------------------------------------- /package_control/downloaders/basic_auth_downloader.py: -------------------------------------------------------------------------------- 1 | import base64 2 | 3 | from urllib.parse import urlparse 4 | 5 | 6 | class BasicAuthDownloader: 7 | 8 | """ 9 | A base for downloaders to add an HTTP basic auth header 10 | """ 11 | 12 | def build_auth_header(self, url): 13 | """ 14 | Constructs an HTTP basic auth header for a URL, if present in 15 | settings 16 | 17 | :param url: 18 | A unicode string of the URL being downloaded 19 | 20 | :return: 21 | A dict with an HTTP header name as the key and the value as the 22 | value. Both are unicode strings. 23 | """ 24 | 25 | auth_string = self.get_auth_string(url) 26 | if not auth_string: 27 | return {} 28 | b64_auth = base64.b64encode(auth_string.encode('utf-8')).decode('utf-8') 29 | return {"Authorization": "Basic %s" % b64_auth} 30 | 31 | def get_auth_string(self, url): 32 | """ 33 | Constructs a string of username:password for use in HTTP basic auth 34 | 35 | :param url: 36 | A unicode string of the URL being downloaded 37 | 38 | :return: 39 | None, or a unicode string of the username:password for the URL 40 | """ 41 | 42 | username, password = self.get_username_password(url) 43 | if username and password: 44 | return "%s:%s" % (username, password) 45 | return None 46 | 47 | def get_username_password(self, url): 48 | """ 49 | Returns a tuple of (username, password) for use in HTTP basic auth 50 | 51 | :param url: 52 | A unicode string of the URL being downloaded 53 | 54 | :return: 55 | A 2-element tuple of either (None, None) or (username, password) 56 | as unicode strings 57 | """ 58 | 59 | domain_name = urlparse(url).netloc 60 | 61 | auth_settings = self.settings.get('http_basic_auth') 62 | if auth_settings and isinstance(auth_settings, dict): 63 | params = auth_settings.get(domain_name) 64 | if params and isinstance(params, (list, tuple)) and len(params) == 2: 65 | return (params[0], params[1]) 66 | return (None, None) 67 | -------------------------------------------------------------------------------- /Main.sublime-menu: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": "tools", 4 | "children": [ 5 | { 6 | "caption": "Packages", 7 | "id": "packages", 8 | "children": [ 9 | { 10 | "caption": "Package Control", 11 | "id": "package-control", 12 | "children": 13 | [ 14 | { 15 | "caption": "New Channel…", 16 | "command": "new_channel_json" 17 | }, 18 | { 19 | "caption": "New Repository…", 20 | "command": "new_repository_json" 21 | } 22 | ] 23 | } 24 | ] 25 | } 26 | ] 27 | }, 28 | { 29 | "id": "preferences", 30 | "children": [ 31 | { 32 | "caption": "Package Settings", 33 | "mnemonic": "P", 34 | "id": "package-settings", 35 | "children": [ 36 | { 37 | "caption": "Package Control", 38 | "children": [ 39 | { 40 | "caption": "Settings", 41 | "command": "edit_settings", 42 | "args": { 43 | "base_file": "${packages}/Package Control/Package Control.sublime-settings", 44 | "default": "// See the left pane for the list of settings and valid values\n{\n\t$0\n}\n" 45 | } 46 | }, 47 | { "caption": "-" } 48 | ] 49 | } 50 | ] 51 | }, 52 | { 53 | "caption": "Package Control", 54 | "mnemonic": "C", 55 | "command": "show_overlay", 56 | "args": {"overlay": "command_palette", "text": "Package Control: "} 57 | } 58 | ] 59 | } 60 | ] 61 | -------------------------------------------------------------------------------- /package_control/commands/add_channel_command.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | import sublime 4 | import sublime_plugin 5 | 6 | from os.path import isabs, normcase, normpath 7 | from urllib.request import pathname2url 8 | 9 | from ..console_write import console_write 10 | from ..settings import pc_settings_filename 11 | from ..show_error import show_error 12 | 13 | 14 | class AddChannelCommand(sublime_plugin.ApplicationCommand): 15 | 16 | """ 17 | A command to add a new channel (list of repositories) to the user's machine 18 | 19 | Example: 20 | 21 | ```py 22 | sublime.run_command( 23 | "add_channel", 24 | { 25 | "url": "https://my-server.com/channel.json", 26 | "unattended": False # if True, suppress error dialogs 27 | } 28 | ) 29 | ``` 30 | """ 31 | 32 | def run(self, url=None, unattended=False): 33 | if isinstance(url, str): 34 | url = url.strip() 35 | 36 | if re.match(r'^(?:file:///|https?://)', url, re.I) is None: 37 | if not isabs(url): 38 | output_fn = console_write if unattended else show_error 39 | output_fn( 40 | ''' 41 | Unable to add the channel "%s" since it does not appear to be 42 | a local URL (file://) or served via HTTP (http:// or https://). 43 | ''', 44 | url 45 | ) 46 | return 47 | 48 | url = "file:" + pathname2url(normcase(normpath(url))) 49 | 50 | settings = sublime.load_settings(pc_settings_filename()) 51 | channels = settings.get('channels') 52 | if not channels: 53 | channels = [] 54 | elif url in channels: 55 | return 56 | channels.append(url) 57 | settings.set('channels', channels) 58 | sublime.save_settings(pc_settings_filename()) 59 | sublime.status_message('Channel %s successfully added' % url) 60 | return 61 | 62 | sublime.active_window().show_input_panel( 63 | 'Channel JSON URL', 64 | '', 65 | self.run, 66 | None, 67 | None 68 | ) 69 | -------------------------------------------------------------------------------- /package_control/settings.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | 3 | 4 | def preferences_filename(): 5 | """ 6 | :return: The appropriate settings filename based on the version of Sublime Text 7 | """ 8 | 9 | return 'Preferences.sublime-settings' 10 | 11 | 12 | def pc_settings_filename(): 13 | """ 14 | :return: The settings file for Package Control 15 | """ 16 | 17 | return 'Package Control.sublime-settings' 18 | 19 | 20 | def load_list_setting(settings, name): 21 | """ 22 | Sometimes users accidentally change settings that should be lists to 23 | just individual strings. This helps fix that. 24 | 25 | :param settings: 26 | A sublime.Settings object 27 | 28 | :param name: 29 | The name of the setting 30 | 31 | :return: 32 | The current value of the setting, always a set 33 | """ 34 | 35 | value = settings.get(name) 36 | if not value: 37 | return set() 38 | if isinstance(value, str): 39 | value = [value] 40 | if not isinstance(value, list): 41 | return set() 42 | 43 | return set(filter(lambda v: isinstance(v, str), value)) 44 | 45 | 46 | def save_list_setting(settings, filename, name, new_value, old_value=None): 47 | """ 48 | Updates a list-valued setting 49 | 50 | :param settings: 51 | The sublime.Settings object 52 | 53 | :param filename: 54 | The settings filename to save in 55 | 56 | :param name: 57 | The setting name 58 | 59 | :param new_value: 60 | The new value for the setting 61 | 62 | :param old_value: 63 | If not None, then this and the new_value will be compared. If they 64 | are the same, the settings will not be flushed to disk. 65 | 66 | :return: 67 | ``True``, if settings have been saved. 68 | ``False``, if ``new_value`` and ``old_value`` were equal. 69 | """ 70 | 71 | if not isinstance(old_value, set): 72 | new_value = set(new_value) 73 | 74 | if old_value is not None: 75 | if not isinstance(old_value, set): 76 | old_value = set(old_value) 77 | if old_value == new_value: 78 | return False 79 | 80 | settings.set(name, sorted(new_value, key=lambda s: s.lower())) 81 | sublime.save_settings(filename) 82 | return True 83 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_asn1.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | # This file exists strictly to make it easier to vendor a combination of 5 | # oscrypto and asn1crypto 6 | 7 | from ..asn1crypto import algos, cms, core, keys, pem, pkcs12, util, x509 8 | 9 | DHParameters = algos.DHParameters 10 | DSASignature = algos.DSASignature 11 | KeyExchangeAlgorithm = algos.KeyExchangeAlgorithm 12 | Pbkdf2Salt = algos.Pbkdf2Salt 13 | 14 | EncryptedData = cms.EncryptedData 15 | 16 | Integer = core.Integer 17 | Null = core.Null 18 | OctetString = core.OctetString 19 | 20 | DSAParams = keys.DSAParams 21 | DSAPrivateKey = keys.DSAPrivateKey 22 | ECDomainParameters = keys.ECDomainParameters 23 | ECPointBitString = keys.ECPointBitString 24 | ECPrivateKey = keys.ECPrivateKey 25 | EncryptedPrivateKeyInfo = keys.EncryptedPrivateKeyInfo 26 | PrivateKeyAlgorithm = keys.PrivateKeyAlgorithm 27 | PrivateKeyInfo = keys.PrivateKeyInfo 28 | PublicKeyAlgorithm = keys.PublicKeyAlgorithm 29 | PublicKeyInfo = keys.PublicKeyInfo 30 | RSAPrivateKey = keys.RSAPrivateKey 31 | RSAPublicKey = keys.RSAPublicKey 32 | 33 | int_from_bytes = util.int_from_bytes 34 | int_to_bytes = util.int_to_bytes 35 | OrderedDict = util.OrderedDict 36 | timezone = util.timezone 37 | 38 | armor = pem.armor 39 | unarmor = pem.unarmor 40 | 41 | CertBag = pkcs12.CertBag 42 | Pfx = pkcs12.Pfx 43 | SafeContents = pkcs12.SafeContents 44 | 45 | Certificate = x509.Certificate 46 | TrustedCertificate = x509.TrustedCertificate 47 | 48 | __all__ = [ 49 | 'armor', 50 | 'CertBag', 51 | 'Certificate', 52 | 'DHParameters', 53 | 'DSAParams', 54 | 'DSAPrivateKey', 55 | 'DSASignature', 56 | 'ECDomainParameters', 57 | 'ECPointBitString', 58 | 'ECPrivateKey', 59 | 'EncryptedData', 60 | 'EncryptedPrivateKeyInfo', 61 | 'int_from_bytes', 62 | 'int_to_bytes', 63 | 'Integer', 64 | 'KeyExchangeAlgorithm', 65 | 'Null', 66 | 'OctetString', 67 | 'OrderedDict', 68 | 'Pbkdf2Salt', 69 | 'Pfx', 70 | 'PrivateKeyAlgorithm', 71 | 'PrivateKeyInfo', 72 | 'PublicKeyAlgorithm', 73 | 'PublicKeyInfo', 74 | 'RSAPrivateKey', 75 | 'RSAPublicKey', 76 | 'SafeContents', 77 | 'timezone', 78 | 'TrustedCertificate', 79 | 'unarmor', 80 | ] 81 | -------------------------------------------------------------------------------- /package_control/commands/add_repository_command.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | import sublime 4 | import sublime_plugin 5 | 6 | from os.path import isabs, normcase, normpath 7 | from urllib.request import pathname2url 8 | 9 | from ..console_write import console_write 10 | from ..settings import pc_settings_filename 11 | from ..show_error import show_error 12 | 13 | 14 | class AddRepositoryCommand(sublime_plugin.ApplicationCommand): 15 | 16 | """ 17 | A command to add a new repository to the user's Package Control settings 18 | 19 | Example: 20 | 21 | ```py 22 | sublime.run_command( 23 | "add_repository", 24 | { 25 | "url": "https://my-server.com/repository.json", 26 | "unattended": False # if True, suppress error dialogs 27 | } 28 | ) 29 | ``` 30 | """ 31 | 32 | def run(self, url=None, unattended=False): 33 | if isinstance(url, str): 34 | url = url.strip() 35 | 36 | if re.match(r'^(?:file:///|https?://)', url, re.I) is None: 37 | if not isabs(url): 38 | output_fn = console_write if unattended else show_error 39 | output_fn( 40 | ''' 41 | Unable to add the repository "%s" since it does not appear to 42 | be a local URL (file://) or served via HTTP (http:// or https://). 43 | ''', 44 | url 45 | ) 46 | return 47 | 48 | url = "file:" + pathname2url(normcase(normpath(url))) 49 | 50 | settings = sublime.load_settings(pc_settings_filename()) 51 | repositories = settings.get('repositories') 52 | if not repositories: 53 | repositories = [] 54 | elif url in repositories: 55 | return 56 | repositories.append(url) 57 | settings.set('repositories', repositories) 58 | sublime.save_settings(pc_settings_filename()) 59 | sublime.status_message('Repository %s successfully added' % url) 60 | return 61 | 62 | sublime.active_window().show_input_panel( 63 | 'GitHub, GitLab, BitBucket or JSON repository URL', 64 | '', 65 | self.run, 66 | None, 67 | None 68 | ) 69 | -------------------------------------------------------------------------------- /package_control/text.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | 3 | from textwrap import dedent 4 | import re 5 | 6 | 7 | def format(string, params=None, strip=True, indent=None): 8 | """ 9 | Takes a multi-line string and does the following: 10 | 11 | - dedents 12 | - removes a single leading newline if the second character is not a newline also 13 | - converts newlines with text before and after into a single line 14 | - removes a single trailing newline if the second-to-laster character is not a newline also 15 | 16 | :param string: 17 | The string to format 18 | 19 | :param params: 20 | Params to interpolate into the string 21 | 22 | :param strip: 23 | If the last newline in the string should be removed 24 | 25 | :param indent: 26 | If all lines should be indented by a set indent after being dedented 27 | 28 | :return: 29 | The formatted string 30 | """ 31 | 32 | output = string 33 | 34 | # Only dedent if not a single-line string. This allows for 35 | # single-line-formatted string to be printed that include intentional 36 | # whitespace. 37 | if output.find('\n') != -1: 38 | output = dedent(output) 39 | 40 | # If the string starts with just a newline, we want to trim it because 41 | # it is a side-effect of the code formatting, but if there are two newlines 42 | # then that means we intended there to be newlines at the beginning 43 | if output[0] == '\n' and output[1] != '\n': 44 | output = output[1:] 45 | 46 | # Unwrap lines, taking into account bulleted lists, ordered lists and 47 | # underlines consisting of = signs 48 | if output.find('\n') != -1: 49 | output = re.sub(r'(?<=\S)\n(?=[^ \n\t\d\*\-=])', ' ', output) 50 | 51 | # By default we want to trim a single trailing newline from a string since 52 | # that is likely from the code formatting, but that trimming is prevented 53 | # if strip == False, or if there are two trailing newlines, which means we 54 | # actually wanted whitespace at the end 55 | if output[-1] == '\n' and strip and output[-2] != '\n': 56 | output = output[0:-1] 57 | 58 | if params is not None: 59 | output = output % params 60 | 61 | if indent is not None: 62 | output = indent + output.replace('\n', '\n' + indent) 63 | 64 | return output 65 | -------------------------------------------------------------------------------- /package_control/http/debuggable_http_response.py: -------------------------------------------------------------------------------- 1 | from http.client import HTTPResponse, IncompleteRead 2 | 3 | from ..console_write import console_write 4 | 5 | 6 | class DebuggableHTTPResponse(HTTPResponse): 7 | 8 | """ 9 | A custom HTTPResponse that formats debugging info for Sublime Text 10 | """ 11 | 12 | _debug_protocol = 'HTTP' 13 | 14 | def __init__(self, sock, debuglevel=0, method=None, **kwargs): 15 | # We have to use a positive debuglevel to get it passed to here, 16 | # however we don't want to use it because by default debugging prints 17 | # to the stdout and we can't capture it, so we use a special -1 value 18 | if debuglevel == 5: 19 | debuglevel = -1 20 | HTTPResponse.__init__(self, sock, debuglevel=debuglevel, method=method) 21 | 22 | def begin(self): 23 | return_value = HTTPResponse.begin(self) 24 | if self.debuglevel == -1: 25 | # Python 2 26 | if hasattr(self.msg, 'headers'): 27 | headers = [line.rstrip() for line in self.msg.headers] 28 | # Python 3 29 | else: 30 | headers = [] 31 | for header in self.msg: 32 | headers.append("%s: %s" % (header, self.msg[header])) 33 | 34 | versions = { 35 | 9: 'HTTP/0.9', 36 | 10: 'HTTP/1.0', 37 | 11: 'HTTP/1.1' 38 | } 39 | status_line = '%s %s %s' % (versions[self.version], str(self.status), self.reason) 40 | headers.insert(0, status_line) 41 | 42 | indented_headers = '\n '.join(headers) 43 | console_write( 44 | ''' 45 | Urllib %s Debug Read 46 | %s 47 | ''', 48 | (self._debug_protocol, indented_headers) 49 | ) 50 | 51 | return return_value 52 | 53 | def is_keep_alive(self): 54 | # Python 2 55 | if hasattr(self.msg, 'headers'): 56 | connection = self.msg.getheader('connection') 57 | # Python 3 58 | else: 59 | connection = self.msg['connection'] 60 | if connection and connection.lower() == 'keep-alive': 61 | return True 62 | return False 63 | 64 | def read(self, *args): 65 | try: 66 | return HTTPResponse.read(self, *args) 67 | except (IncompleteRead) as e: 68 | return e.partial 69 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/errors.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import sys 5 | import socket 6 | 7 | 8 | __all__ = [ 9 | 'AsymmetricKeyError', 10 | 'CACertsError', 11 | 'LibraryNotFoundError', 12 | 'SignatureError', 13 | 'TLSError', 14 | 'TLSConnectionError', 15 | 'TLSDisconnectError', 16 | 'TLSGracefulDisconnectError', 17 | 'TLSVerificationError', 18 | ] 19 | 20 | 21 | class LibraryNotFoundError(Exception): 22 | 23 | """ 24 | An exception when trying to find a shared library 25 | """ 26 | 27 | pass 28 | 29 | 30 | class SignatureError(Exception): 31 | 32 | """ 33 | An exception when validating a signature 34 | """ 35 | 36 | pass 37 | 38 | 39 | class AsymmetricKeyError(Exception): 40 | 41 | """ 42 | An exception when a key is invalid or unsupported 43 | """ 44 | 45 | pass 46 | 47 | 48 | class IncompleteAsymmetricKeyError(AsymmetricKeyError): 49 | 50 | """ 51 | An exception when a key is missing necessary information 52 | """ 53 | 54 | pass 55 | 56 | 57 | class CACertsError(Exception): 58 | 59 | """ 60 | An exception when exporting CA certs from the OS trust store 61 | """ 62 | 63 | pass 64 | 65 | 66 | class TLSError(socket.error): 67 | 68 | """ 69 | An exception related to TLS functionality 70 | """ 71 | 72 | message = None 73 | 74 | def __init__(self, message): 75 | self.args = (message,) 76 | self.message = message 77 | 78 | def __str__(self): 79 | output = self.__unicode__() 80 | if sys.version_info < (3,): 81 | output = output.encode('utf-8') 82 | return output 83 | 84 | def __unicode__(self): 85 | return self.message 86 | 87 | 88 | class TLSConnectionError(TLSError): 89 | pass 90 | 91 | 92 | class TLSDisconnectError(TLSConnectionError): 93 | pass 94 | 95 | 96 | class TLSGracefulDisconnectError(TLSDisconnectError): 97 | pass 98 | 99 | 100 | class TLSVerificationError(TLSError): 101 | 102 | """ 103 | A server certificate verification error happened during a TLS handshake 104 | """ 105 | 106 | certificate = None 107 | 108 | def __init__(self, message, certificate): 109 | TLSError.__init__(self, message) 110 | self.certificate = certificate 111 | self.args = (message, certificate) 112 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Package Control 2 | 3 | The [Sublime Text](http://www.sublimetext.com) package manager. 4 | It allows users to find, install and keep packages up to date. 5 | 6 | ## Installation 7 | 8 | To install: 9 | 10 | - Open the command palette and type "Install Package Control" 11 | - or, use the menu *Tools > Install Package Control* 12 | 13 | Until Package Control 4.0 is available via packagecontrol.io, call the following command from Sublime Text's console. 14 | 15 | ```py 16 | from urllib.request import urlretrieve;urlretrieve(url="https://github.com/wbond/package_control/releases/latest/download/Package.Control.sublime-package", filename=sublime.installed_packages_path() + '/Package Control.sublime-package') 17 | ``` 18 | 19 | ## Usage 20 | 21 | All of the primary features of Package Control are exposed through the command palette. 22 | 23 | To install a package: 24 | 25 | - Open the command palette 26 | - Type "Install Package" 27 | - Select a package from the list 28 | 29 | For more features, see https://packagecontrol.io/docs/usage. 30 | 31 | ## Documentation 32 | 33 | The documentation for Package Control can be found at https://packagecontrol.io/docs. 34 | 35 | ## Bug Reports 36 | 37 | If you find a bug with Package Control, please follow the directions at https://packagecontrol.io/docs/issues to submit an issue. 38 | 39 | ## License 40 | 41 | Package Control is licensed under the MIT license. 42 | 43 | ``` 44 | Copyright (c) 2011-2023 Will Bond 45 | 46 | Permission is hereby granted, free of charge, to any person obtaining a copy 47 | of this software and associated documentation files (the "Software"), to deal 48 | in the Software without restriction, including without limitation the rights 49 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 50 | copies of the Software, and to permit persons to whom the Software is 51 | furnished to do so, subject to the following conditions: 52 | 53 | The above copyright notice and this permission notice shall be included in 54 | all copies or substantial portions of the Software. 55 | 56 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 57 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 58 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 59 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 60 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 61 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 62 | THE SOFTWARE. 63 | ``` 64 | -------------------------------------------------------------------------------- /package_control/deps/asn1crypto/pdf.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | ASN.1 type classes for PDF signature structures. Adds extra oid mapping and 5 | value parsing to asn1crypto.x509.Extension() and asn1crypto.xms.CMSAttribute(). 6 | """ 7 | 8 | from __future__ import unicode_literals, division, absolute_import, print_function 9 | 10 | from .cms import CMSAttributeType, CMSAttribute 11 | from .core import ( 12 | Boolean, 13 | Integer, 14 | Null, 15 | ObjectIdentifier, 16 | OctetString, 17 | Sequence, 18 | SequenceOf, 19 | SetOf, 20 | ) 21 | from .crl import CertificateList 22 | from .ocsp import OCSPResponse 23 | from .x509 import ( 24 | Extension, 25 | ExtensionId, 26 | GeneralName, 27 | KeyPurposeId, 28 | ) 29 | 30 | 31 | class AdobeArchiveRevInfo(Sequence): 32 | _fields = [ 33 | ('version', Integer) 34 | ] 35 | 36 | 37 | class AdobeTimestamp(Sequence): 38 | _fields = [ 39 | ('version', Integer), 40 | ('location', GeneralName), 41 | ('requires_auth', Boolean, {'optional': True, 'default': False}), 42 | ] 43 | 44 | 45 | class OtherRevInfo(Sequence): 46 | _fields = [ 47 | ('type', ObjectIdentifier), 48 | ('value', OctetString), 49 | ] 50 | 51 | 52 | class SequenceOfCertificateList(SequenceOf): 53 | _child_spec = CertificateList 54 | 55 | 56 | class SequenceOfOCSPResponse(SequenceOf): 57 | _child_spec = OCSPResponse 58 | 59 | 60 | class SequenceOfOtherRevInfo(SequenceOf): 61 | _child_spec = OtherRevInfo 62 | 63 | 64 | class RevocationInfoArchival(Sequence): 65 | _fields = [ 66 | ('crl', SequenceOfCertificateList, {'explicit': 0, 'optional': True}), 67 | ('ocsp', SequenceOfOCSPResponse, {'explicit': 1, 'optional': True}), 68 | ('other_rev_info', SequenceOfOtherRevInfo, {'explicit': 2, 'optional': True}), 69 | ] 70 | 71 | 72 | class SetOfRevocationInfoArchival(SetOf): 73 | _child_spec = RevocationInfoArchival 74 | 75 | 76 | ExtensionId._map['1.2.840.113583.1.1.9.2'] = 'adobe_archive_rev_info' 77 | ExtensionId._map['1.2.840.113583.1.1.9.1'] = 'adobe_timestamp' 78 | ExtensionId._map['1.2.840.113583.1.1.10'] = 'adobe_ppklite_credential' 79 | Extension._oid_specs['adobe_archive_rev_info'] = AdobeArchiveRevInfo 80 | Extension._oid_specs['adobe_timestamp'] = AdobeTimestamp 81 | Extension._oid_specs['adobe_ppklite_credential'] = Null 82 | KeyPurposeId._map['1.2.840.113583.1.1.5'] = 'pdf_signing' 83 | CMSAttributeType._map['1.2.840.113583.1.1.8'] = 'adobe_revocation_info_archival' 84 | CMSAttribute._oid_specs['adobe_revocation_info_archival'] = SetOfRevocationInfoArchival 85 | -------------------------------------------------------------------------------- /package_control/http/debuggable_http_connection.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from http.client import HTTPConnection 3 | 4 | from ..console_write import console_write 5 | from .debuggable_http_response import DebuggableHTTPResponse 6 | 7 | 8 | class DebuggableHTTPConnection(HTTPConnection): 9 | 10 | """ 11 | A custom HTTPConnection that formats debugging info for Sublime Text 12 | """ 13 | 14 | response_class = DebuggableHTTPResponse 15 | _debug_protocol = 'HTTP' 16 | 17 | def __init__(self, host, port=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, **kwargs): 18 | if 'debug' in kwargs and kwargs['debug']: 19 | self.debuglevel = 5 20 | elif 'debuglevel' in kwargs: 21 | self.debuglevel = kwargs['debuglevel'] 22 | 23 | HTTPConnection.__init__(self, host, port=port, timeout=timeout) 24 | 25 | def connect(self): 26 | if self.debuglevel == -1: 27 | console_write( 28 | ''' 29 | Urllib %s Debug General 30 | Connecting to %s on port %s 31 | ''', 32 | (self._debug_protocol, self.host, self.port) 33 | ) 34 | HTTPConnection.connect(self) 35 | 36 | def send(self, string): 37 | # We have to use a positive debuglevel to get it passed to the 38 | # HTTPResponse object, however we don't want to use it because by 39 | # default debugging prints to the stdout and we can't capture it, so 40 | # we temporarily set it to -1 for the standard httplib code 41 | reset_debug = False 42 | if self.debuglevel == 5: 43 | reset_debug = 5 44 | self.debuglevel = -1 45 | HTTPConnection.send(self, string) 46 | if reset_debug or self.debuglevel == -1: 47 | if len(string.strip()) > 0: 48 | unicode_string = string.strip().decode('iso-8859-1') 49 | indented_headers = '\n '.join(unicode_string.splitlines()) 50 | console_write( 51 | ''' 52 | Urllib %s Debug Write 53 | %s 54 | ''', 55 | (self._debug_protocol, indented_headers) 56 | ) 57 | if reset_debug: 58 | self.debuglevel = reset_debug 59 | 60 | def request(self, method, url, body=None, headers={}): 61 | # By default urllib2 and urllib.request override the Connection header, 62 | # however, it is preferred to be able to re-use it 63 | headers['Connection'] = 'Keep-Alive' 64 | 65 | HTTPConnection.request(self, method, url, body, headers) 66 | -------------------------------------------------------------------------------- /package_control/clients/readme_client.py: -------------------------------------------------------------------------------- 1 | import re 2 | import os 3 | import base64 4 | from urllib.parse import urlencode 5 | 6 | from .json_api_client import JSONApiClient 7 | 8 | 9 | # Used to map file extensions to formats 10 | _readme_formats = { 11 | '.md': 'markdown', 12 | '.mkd': 'markdown', 13 | '.mdown': 'markdown', 14 | '.markdown': 'markdown', 15 | '.textile': 'textile', 16 | '.creole': 'creole', 17 | '.rst': 'rst' 18 | } 19 | 20 | 21 | class ReadmeClient(JSONApiClient): 22 | 23 | def readme_info(self, url): 24 | """ 25 | Retrieve the readme and info about it 26 | 27 | :param url: 28 | The URL of the readme file 29 | 30 | :raises: 31 | DownloaderException: if there is an error downloading the readme 32 | ClientException: if there is an error parsing the response 33 | 34 | :return: 35 | A dict with the following keys: 36 | `filename` 37 | `format` - `markdown`, `textile`, `creole`, `rst` or `txt` 38 | `contents` - contents of the readme as str/unicode 39 | """ 40 | 41 | contents = None 42 | 43 | # Try to grab the contents of a GitHub-based readme by grabbing the cached 44 | # content of the readme API call 45 | github_match = re.match( 46 | r'https://raw\.github(?:usercontent)?\.com/([^/#?]+/[^/#?]+)/([^/#?]+)/' 47 | r'readme(\.(md|mkd|mdown|markdown|textile|creole|rst|txt))?$', 48 | url, 49 | re.I 50 | ) 51 | if github_match: 52 | user_repo = github_match.group(1) 53 | branch = github_match.group(2) 54 | 55 | query_string = urlencode({'ref': branch}) 56 | readme_json_url = 'https://api.github.com/repos/%s/readme?%s' % (user_repo, query_string) 57 | try: 58 | info = self.fetch_json(readme_json_url) 59 | contents = base64.b64decode(info['content']) 60 | except (ValueError): 61 | pass 62 | 63 | if not contents: 64 | contents = self.fetch(url) 65 | 66 | _, ext = os.path.splitext(url) 67 | format = 'txt' 68 | ext = ext.lower() 69 | if ext in _readme_formats: 70 | format = _readme_formats[ext] 71 | 72 | try: 73 | contents = contents.decode('utf-8') 74 | except (UnicodeDecodeError): 75 | contents = contents.decode('cp1252', errors='replace') 76 | 77 | return { 78 | 'filename': os.path.basename(url), 79 | 'format': format, 80 | 'contents': contents 81 | } 82 | -------------------------------------------------------------------------------- /package_control/selectors.py: -------------------------------------------------------------------------------- 1 | import re 2 | import sublime 3 | 4 | PLATFORM_SELECTORS = ( 5 | sublime.platform() + '-' + sublime.arch(), 6 | sublime.platform(), 7 | '*' 8 | ) 9 | 10 | ST_VERSION = int(sublime.version()) 11 | 12 | 13 | def get_compatible_platform(platforms, platform_selectors=PLATFORM_SELECTORS): 14 | """ 15 | Gets the platform, which is compatible with OS. 16 | 17 | :param platforms: 18 | A list of platforms to choose from 19 | 20 | :param platform_selectors: 21 | A list of platform selectors to match against 22 | Defaults to ``PLATFORM_SELECTORS`` 23 | 24 | :returns: 25 | The compatible platform from ``platforms`` or 26 | False, if none was found in ``platforms`` 27 | """ 28 | 29 | if not isinstance(platforms, list): 30 | platforms = [platforms] 31 | 32 | for selector in platform_selectors: 33 | if selector in platforms: 34 | return selector 35 | 36 | return False 37 | 38 | 39 | def is_compatible_platform(platforms, platform_selectors=PLATFORM_SELECTORS): 40 | """ 41 | Checks if platforms are compatible with OS. 42 | 43 | :param platforms: 44 | A list of platforms to choose from 45 | 46 | :param platform_selectors: 47 | A list of platform selectors to match against 48 | Defaults to ``PLATFORM_SELECTORS`` 49 | 50 | :returns: 51 | True, if a compatible platform was found in ``platforms`` 52 | False, if none was found 53 | """ 54 | 55 | return bool(get_compatible_platform(platforms, platform_selectors)) 56 | 57 | 58 | def is_compatible_version(version_range, st_version=ST_VERSION): 59 | """ 60 | Determines if current ST version is covered by given version range. 61 | 62 | :param version_range: 63 | The version range expression to match ST version against. 64 | 65 | Examples: ">4000", ">=4000", "<4000", "<=4000", "4000 - 4100" 66 | 67 | :param st_version: 68 | The ST version to evaluate. Defaults to ``ST_VERSION`` 69 | 70 | :returns: 71 | True if compatible version, False otherwise. 72 | """ 73 | 74 | if version_range == '*': 75 | return True 76 | 77 | match = re.match(r'([<>]=?)(\d{4})$', version_range) 78 | if match: 79 | op, ver = match.groups() 80 | if op == '>': 81 | return st_version > int(ver) 82 | if op == '>=': 83 | return st_version >= int(ver) 84 | if op == '<': 85 | return st_version < int(ver) 86 | if op == '<=': 87 | return st_version <= int(ver) 88 | 89 | match = re.match(r'(\d{4}) - (\d{4})$', version_range) 90 | if match: 91 | return st_version >= int(match.group(1)) and st_version <= int(match.group(2)) 92 | 93 | return None 94 | -------------------------------------------------------------------------------- /package_control/commands/upgrade_package_command.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | import sublime 4 | import sublime_plugin 5 | 6 | from ..activity_indicator import ActivityIndicator 7 | from ..console_write import console_write 8 | from ..package_tasks import USE_QUICK_PANEL_ITEM, PackageTaskRunner 9 | from ..show_error import show_message 10 | 11 | 12 | class UpgradePackageCommand(sublime_plugin.ApplicationCommand): 13 | 14 | """ 15 | A command that presents the list of installed packages that can be upgraded 16 | """ 17 | 18 | def run(self): 19 | 20 | def show_quick_panel(): 21 | upgrader = PackageTaskRunner() 22 | 23 | with ActivityIndicator('Searching updates...') as progress: 24 | tasks = upgrader.create_package_tasks( 25 | actions=(upgrader.PULL, upgrader.UPGRADE), 26 | ignore_packages=upgrader.ignored_packages() # don't upgrade disabled packages 27 | ) 28 | if tasks is False: 29 | message = 'There are no packages available for upgrade' 30 | console_write(message) 31 | progress.finish(message) 32 | show_message( 33 | ''' 34 | %s 35 | 36 | Please see https://packagecontrol.io/docs/troubleshooting for help 37 | ''', 38 | message 39 | ) 40 | return 41 | 42 | if not tasks: 43 | message = 'All packages up-to-date!' 44 | console_write(message) 45 | progress.finish(message) 46 | show_message(message) 47 | return 48 | 49 | def on_done(picked): 50 | if picked == -1: 51 | return 52 | 53 | def worker(tasks): 54 | with ActivityIndicator('Preparing...') as progress: 55 | upgrader.run_upgrade_tasks(tasks, progress) 56 | 57 | threading.Thread( 58 | target=worker, 59 | args=[[tasks[picked - 1]] if picked > 0 else tasks] 60 | ).start() 61 | 62 | items = upgrader.render_quick_panel_items(tasks) 63 | 64 | if USE_QUICK_PANEL_ITEM: 65 | items.insert(0, sublime.QuickPanelItem( 66 | "Upgrade All Packages", 67 | "Use this command to install all available upgrades." 68 | )) 69 | else: 70 | items.insert(0, [ 71 | "Upgrade All Packages", 72 | "Use this command to install all available upgrades.", 73 | "" 74 | ]) 75 | 76 | sublime.active_window().show_quick_panel( 77 | items, 78 | on_done, 79 | sublime.KEEP_OPEN_ON_FOCUS_LOST 80 | ) 81 | 82 | threading.Thread(target=show_quick_panel).start() 83 | -------------------------------------------------------------------------------- /package_control/commands/__init__.py: -------------------------------------------------------------------------------- 1 | from .add_channel_command import AddChannelCommand 2 | from .add_repository_command import AddRepositoryCommand 3 | from .clear_package_cache_command import ClearPackageCacheCommand 4 | from .create_package_command import CreatePackageCommand 5 | from .disable_package_command import DisablePackageCommand 6 | from .disable_packages_command import DisablePackagesCommand 7 | from .discover_packages_command import DiscoverPackagesCommand 8 | from .enable_package_command import EnablePackageCommand 9 | from .enable_packages_command import EnablePackagesCommand 10 | from .install_package_command import InstallPackageCommand 11 | from .install_packages_command import InstallPackagesCommand 12 | from .list_available_libraries_command import ListAvailableLibrariesCommand 13 | from .list_packages_command import ListPackagesCommand 14 | from .list_unmanaged_packages_command import ListUnmanagedPackagesCommand 15 | from .new_template_command import NewChannelJsonCommand 16 | from .new_template_command import NewRepositoryJsonCommand 17 | from .package_control_disable_debug_mode_command import PackageControlDisableDebugModeCommand 18 | from .package_control_enable_debug_mode_command import PackageControlEnableDebugModeCommand 19 | from .package_control_insert_command import PackageControlInsertCommand 20 | from .package_control_message_command import PackageControlMessageCommand 21 | from .remove_channel_command import RemoveChannelCommand 22 | from .remove_package_command import RemovePackageCommand 23 | from .remove_packages_command import RemovePackagesCommand 24 | from .remove_repository_command import RemoveRepositoryCommand 25 | from .revert_package_command import RevertPackageCommand 26 | from .satisfy_libraries_command import SatisfyLibrariesCommand 27 | from .satisfy_packages_command import SatisfyPackagesCommand 28 | from .upgrade_all_packages_command import UpgradeAllPackagesCommand 29 | from .upgrade_package_command import UpgradePackageCommand 30 | from .upgrade_packages_command import UpgradePackagesCommand 31 | 32 | 33 | __all__ = [ 34 | 'AddChannelCommand', 35 | 'AddRepositoryCommand', 36 | 'ClearPackageCacheCommand', 37 | 'CreatePackageCommand', 38 | 'DisablePackageCommand', 39 | 'DisablePackagesCommand', 40 | 'DiscoverPackagesCommand', 41 | 'EnablePackageCommand', 42 | 'EnablePackagesCommand', 43 | 'InstallPackageCommand', 44 | 'InstallPackagesCommand', 45 | 'ListAvailableLibrariesCommand', 46 | 'ListPackagesCommand', 47 | 'ListUnmanagedPackagesCommand', 48 | 'NewChannelJsonCommand', 49 | 'NewRepositoryJsonCommand', 50 | 'PackageControlDisableDebugModeCommand', 51 | 'PackageControlEnableDebugModeCommand', 52 | 'PackageControlInsertCommand', 53 | 'PackageControlMessageCommand', 54 | 'RemoveChannelCommand', 55 | 'RemovePackageCommand', 56 | 'RemovePackagesCommand', 57 | 'RemoveRepositoryCommand', 58 | 'RevertPackageCommand', 59 | 'SatisfyLibrariesCommand', 60 | 'SatisfyPackagesCommand', 61 | 'UpgradeAllPackagesCommand', 62 | 'UpgradePackageCommand', 63 | 'UpgradePackagesCommand', 64 | ] 65 | -------------------------------------------------------------------------------- /package_control/downloaders/cli_downloader.py: -------------------------------------------------------------------------------- 1 | import os 2 | import subprocess 3 | 4 | from ..console_write import console_write 5 | from ..cmd import create_cmd 6 | from .non_clean_exit_error import NonCleanExitError 7 | from .binary_not_found_error import BinaryNotFoundError 8 | 9 | 10 | class CliDownloader: 11 | 12 | """ 13 | Base for downloaders that use a command line program 14 | 15 | :param settings: 16 | A dict of the various Package Control settings. The Sublime Text 17 | Settings API is not used because this code is run in a thread. 18 | """ 19 | 20 | def __init__(self, settings): 21 | self.settings = settings 22 | 23 | def clean_tmp_file(self): 24 | if os.path.exists(self.tmp_file): 25 | os.remove(self.tmp_file) 26 | 27 | def find_binary(self, name): 28 | """ 29 | Finds the given executable name in the system PATH 30 | 31 | :param name: 32 | The exact name of the executable to find 33 | 34 | :return: 35 | The absolute path to the executable 36 | 37 | :raises: 38 | BinaryNotFoundError when the executable can not be found 39 | """ 40 | 41 | dirs = os.environ['PATH'].split(os.pathsep) 42 | if os.name != 'nt': 43 | # This is mostly for OS X, which seems to launch ST with a 44 | # minimal set of environmental variables 45 | dirs.append('/usr/local/bin') 46 | executable = name 47 | else: 48 | executable = name + ".exe" 49 | 50 | for dir_ in dirs: 51 | path = os.path.join(dir_, executable) 52 | if os.path.exists(path): 53 | return path 54 | 55 | raise BinaryNotFoundError('The binary %s could not be located' % executable) 56 | 57 | def execute(self, args): 58 | """ 59 | Runs the executable and args and returns the result 60 | 61 | :param args: 62 | A list of the executable path and all arguments to be passed to it 63 | 64 | :return: 65 | The text output of the executable 66 | 67 | :raises: 68 | NonCleanExitError when the executable exits with an error 69 | """ 70 | 71 | if self.settings.get('debug'): 72 | console_write( 73 | ''' 74 | Trying to execute command %s 75 | ''', 76 | create_cmd(args) 77 | ) 78 | 79 | startupinfo = None 80 | if os.name == 'nt': 81 | startupinfo = subprocess.STARTUPINFO() 82 | startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW 83 | 84 | proc = subprocess.Popen( 85 | args, startupinfo=startupinfo, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 86 | 87 | output, self.stderr = proc.communicate() 88 | 89 | if proc.returncode != 0: 90 | error = NonCleanExitError(proc.returncode) 91 | error.stderr = self.stderr 92 | error.stdout = output 93 | raise error 94 | return output 95 | -------------------------------------------------------------------------------- /package_control/upgraders/hg_upgrader.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from ..cache import set_cache, get_cache 4 | from ..show_error import show_error 5 | from .vcs_upgrader import VcsUpgrader 6 | 7 | 8 | class HgUpgrader(VcsUpgrader): 9 | 10 | """ 11 | Allows upgrading a local mercurial-repository-based package 12 | """ 13 | 14 | cli_name = 'hg' 15 | 16 | ok_returncodes = set([0, 1]) 17 | 18 | def retrieve_binary(self): 19 | """ 20 | Returns the path to the hg executable 21 | 22 | :return: The string path to the executable or False on error 23 | """ 24 | 25 | name = 'hg' 26 | if os.name == 'nt': 27 | name += '.exe' 28 | binary = self.find_binary(name) 29 | 30 | if not binary: 31 | show_error( 32 | ''' 33 | Unable to find %s. 34 | 35 | Please set the "hg_binary" setting by accessing the 36 | Preferences > Package Settings > Package Control > Settings 37 | \u2013 User menu entry. 38 | 39 | The Settings \u2013 Default entry can be used for reference, 40 | but changes to that will be overwritten upon next upgrade. 41 | ''', 42 | name 43 | ) 44 | return False 45 | 46 | return binary 47 | 48 | def run(self): 49 | """ 50 | Updates the repository with remote changes 51 | 52 | :return: False or error, or True on success 53 | """ 54 | 55 | binary = self.retrieve_binary() 56 | if not binary: 57 | return False 58 | args = [binary] 59 | args.extend(self.update_command) 60 | args.append('default') 61 | result = self.execute(args, self.working_copy, meaningful_output=True) 62 | if result is not False: 63 | cache_key = self.working_copy + '.incoming' 64 | set_cache(cache_key, None, 0) 65 | 66 | return True 67 | 68 | def incoming(self): 69 | """:return: bool if remote revisions are available""" 70 | 71 | cache_key = self.working_copy + '.incoming' 72 | incoming = get_cache(cache_key) 73 | if incoming is not None: 74 | return incoming 75 | 76 | binary = self.retrieve_binary() 77 | if not binary: 78 | return False 79 | 80 | args = [binary, 'in', '-q', 'default'] 81 | output = self.execute(args, self.working_copy, meaningful_output=True) 82 | if output is False: 83 | return False 84 | 85 | incoming = len(output) > 0 86 | 87 | set_cache(cache_key, incoming, self.cache_length) 88 | return incoming 89 | 90 | def latest_commit(self): 91 | """ 92 | :return: 93 | The latest commit hash 94 | """ 95 | 96 | binary = self.retrieve_binary() 97 | if not binary: 98 | return False 99 | 100 | args = [binary, 'id', '-i'] 101 | output = self.execute(args, self.working_copy) 102 | if output is False: 103 | return False 104 | 105 | return output.strip() 106 | -------------------------------------------------------------------------------- /package_control/processes.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | __all__ = ['list_process_names'] 4 | 5 | if os.name == 'nt': 6 | import ctypes 7 | from ctypes import windll, wintypes, POINTER, sizeof, byref, cast 8 | 9 | psapi = windll.psapi 10 | kernel32 = windll.kernel32 11 | 12 | if not hasattr(wintypes, 'PDWORD'): 13 | wintypes.PDWORD = POINTER(wintypes.DWORD) 14 | wintypes.LPDWORD = wintypes.PDWORD 15 | 16 | PHModule = POINTER(wintypes.HANDLE) 17 | 18 | PROCESS_QUERY_INFORMATION = 0x0400 19 | PROCESS_VM_READ = 0x0010 20 | 21 | psapi.EnumProcesses.argtypes = [wintypes.PDWORD, wintypes.DWORD, wintypes.PDWORD] 22 | psapi.EnumProcesses.restype = wintypes.BOOL 23 | 24 | kernel32.OpenProcess.argtypes = [wintypes.DWORD, wintypes.BOOL, wintypes.DWORD] 25 | kernel32.OpenProcess.restype = wintypes.HANDLE 26 | 27 | kernel32.CloseHandle.argtypes = [wintypes.HANDLE] 28 | kernel32.CloseHandle.restype = wintypes.BOOL 29 | 30 | psapi.EnumProcessModules.argtypes = [wintypes.HANDLE, PHModule, wintypes.DWORD, POINTER(wintypes.LPDWORD)] 31 | psapi.EnumProcessModules.restype = wintypes.BOOL 32 | 33 | psapi.GetModuleBaseNameW.argtypes = [wintypes.HANDLE, wintypes.HANDLE, wintypes.LPWSTR, wintypes.DWORD] 34 | psapi.GetModuleBaseNameW.restype = wintypes.DWORD 35 | 36 | def list_process_names(): 37 | """ 38 | List names of running processes. 39 | 40 | :return: 41 | A generator of process names 42 | """ 43 | 44 | process_ids = [] 45 | process_id_array_size = 1024 46 | entries = 0 47 | 48 | while entries == 0 or process_id_array_size == entries: 49 | dword_array = (wintypes.DWORD * process_id_array_size) 50 | 51 | process_ids = dword_array() 52 | bytes_used = wintypes.DWORD(0) 53 | 54 | res = psapi.EnumProcesses(cast(process_ids, wintypes.PDWORD), sizeof(process_ids), byref(bytes_used)) 55 | if not res: 56 | return 57 | 58 | entries = int(bytes_used.value / sizeof(wintypes.DWORD)) 59 | process_id_array_size += 512 60 | 61 | for process_id in process_ids[:entries]: 62 | process_handle = kernel32.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, False, process_id) 63 | if process_handle: 64 | module = wintypes.HANDLE() 65 | needed_bytes = wintypes.LPDWORD() 66 | module_res = psapi.EnumProcessModules( 67 | process_handle, 68 | byref(module), 69 | sizeof(module), 70 | byref(needed_bytes) 71 | ) 72 | if module_res: 73 | length = 260 74 | buffer = ctypes.create_unicode_buffer(length) 75 | psapi.GetModuleBaseNameW(process_handle, module, buffer, length) 76 | kernel32.CloseHandle(process_handle) 77 | name = buffer.value 78 | yield name.lower() 79 | continue 80 | kernel32.CloseHandle(process_handle) 81 | 82 | else: 83 | 84 | def list_process_names(): 85 | """ 86 | Stub for posix machines, unimplemented since it is not needed 87 | """ 88 | 89 | return [] 90 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_openssl/_libssl.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import re 5 | import sys 6 | 7 | from .. import ffi, _backend_config 8 | 9 | # Initialize OpenSSL 10 | from ._libcrypto import libcrypto_version_info 11 | 12 | if ffi() == 'cffi': 13 | from ._libssl_cffi import libssl 14 | else: 15 | from ._libssl_ctypes import libssl 16 | 17 | 18 | __all__ = [ 19 | 'libssl', 20 | 'LibsslConst', 21 | 'error_code_version_info', 22 | ] 23 | 24 | 25 | if libcrypto_version_info < (1, 1): 26 | libssl.SSL_library_init() 27 | # Enables SHA2 algorithms on 0.9.8n and older 28 | if libcrypto_version_info < (1, 0): 29 | libssl.OPENSSL_add_all_algorithms_noconf() 30 | 31 | 32 | class LibsslConst(): 33 | ERR_LIB_ASN1 = 13 34 | ERR_LIB_SSL = 20 35 | 36 | SSL_CTRL_OPTIONS = 32 37 | SSL_CTRL_SET_SESS_CACHE_MODE = 44 38 | 39 | SSL_VERIFY_NONE = 0 40 | SSL_VERIFY_PEER = 1 41 | 42 | SSL_ST_OK = 3 43 | 44 | SSL_ERROR_WANT_READ = 2 45 | SSL_ERROR_WANT_WRITE = 3 46 | SSL_ERROR_ZERO_RETURN = 6 47 | 48 | SSL_OP_NO_SSLv2 = 0x01000000 49 | SSL_OP_NO_SSLv3 = 0x02000000 50 | SSL_OP_NO_TLSv1 = 0x04000000 51 | SSL_OP_NO_TLSv1_2 = 0x08000000 52 | SSL_OP_NO_TLSv1_1 = 0x10000000 53 | 54 | SSL_SESS_CACHE_CLIENT = 0x0001 55 | 56 | SSL_R_NO_SHARED_CIPHER = 193 57 | 58 | SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM = 130 59 | SSL_F_SSL3_GET_KEY_EXCHANGE = 141 60 | SSL_F_SSL3_GET_SERVER_CERTIFICATE = 144 61 | SSL_R_BAD_DH_P_LENGTH = 110 62 | SSL_R_CERTIFICATE_VERIFY_FAILED = 134 63 | SSL_R_UNKNOWN_PROTOCOL = 252 64 | SSL_R_DH_KEY_TOO_SMALL = 372 65 | 66 | # OpenSSL 1.1.0 67 | SSL_F_TLS_PROCESS_SKE_DHE = 419 68 | SSL_F_SSL3_GET_RECORD = 143 69 | SSL_R_WRONG_VERSION_NUMBER = 267 70 | SSL_F_TLS_PROCESS_SERVER_CERTIFICATE = 367 71 | 72 | # OpenSSL < 1.1.0 73 | SSL_F_SSL23_GET_SERVER_HELLO = 119 74 | SSL_F_SSL3_READ_BYTES = 148 75 | SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE = 1040 76 | SSL_R_TLSV1_ALERT_PROTOCOL_VERSION = 1070 77 | 78 | SSL_CTRL_SET_TLSEXT_HOSTNAME = 55 79 | TLSEXT_NAMETYPE_host_name = 0 80 | 81 | X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY = 20 82 | X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN = 19 83 | X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT = 18 84 | 85 | X509_V_ERR_CERT_NOT_YET_VALID = 9 86 | X509_V_ERR_CERT_HAS_EXPIRED = 10 87 | 88 | ASN1_F_ASN1_ITEM_VERIFY = 197 89 | ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM = 161 90 | 91 | 92 | if libcrypto_version_info >= (1, 1, 0): 93 | LibsslConst.SSL_R_DH_KEY_TOO_SMALL = 394 94 | 95 | 96 | error_code_version_info = libcrypto_version_info 97 | # The Apple version of libssl seems to have changed various codes for 98 | # some reason, but the rest of the API is still OpenSSL 1.0.1 99 | if sys.platform == 'darwin': 100 | libssl_abi_match = re.match(r'/usr/lib/libssl\.(\d+)', _backend_config().get('libssl_path', '')) 101 | if libssl_abi_match and int(libssl_abi_match.group(1)) >= 44: 102 | LibsslConst.SSL_F_TLS_PROCESS_SERVER_CERTIFICATE = 7 103 | LibsslConst.SSL_F_SSL3_GET_KEY_EXCHANGE = 9 104 | LibsslConst.SSL_F_SSL3_READ_BYTES = 4 105 | LibsslConst.SSL_F_SSL3_GET_RECORD = 4 106 | LibsslConst.SSL_F_SSL23_GET_SERVER_HELLO = 4 107 | error_code_version_info = (1, 1, 0) 108 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_openssl/_libssl_cffi.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .. import _backend_config 5 | from .._ffi import get_library, register_ffi 6 | from ..errors import LibraryNotFoundError 7 | from ._libcrypto import libcrypto_version_info 8 | 9 | from cffi import FFI 10 | 11 | 12 | __all__ = [ 13 | 'libssl', 14 | ] 15 | 16 | 17 | ffi = FFI() 18 | 19 | libssl_path = _backend_config().get('libssl_path') 20 | if libssl_path is None: 21 | libssl_path = get_library('ssl', 'libssl', '44') 22 | if not libssl_path: 23 | raise LibraryNotFoundError('The library libssl could not be found') 24 | 25 | libssl = ffi.dlopen(libssl_path) 26 | register_ffi(libssl, ffi) 27 | 28 | ffi.cdef(""" 29 | typedef ... SSL_METHOD; 30 | typedef uintptr_t SSL_CTX; 31 | typedef ... SSL_SESSION; 32 | typedef uintptr_t SSL; 33 | typedef ... BIO_METHOD; 34 | typedef uintptr_t BIO; 35 | typedef uintptr_t X509; 36 | typedef ... X509_STORE; 37 | typedef ... X509_STORE_CTX; 38 | typedef uintptr_t _STACK; 39 | 40 | BIO_METHOD *BIO_s_mem(void); 41 | BIO *BIO_new(BIO_METHOD *type); 42 | int BIO_free(BIO *a); 43 | int BIO_read(BIO *b, void *buf, int len); 44 | int BIO_write(BIO *b, const void *buf, int len); 45 | size_t BIO_ctrl_pending(BIO *b); 46 | 47 | SSL_CTX *SSL_CTX_new(const SSL_METHOD *method); 48 | long SSL_CTX_set_timeout(SSL_CTX *ctx, long t); 49 | void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, 50 | int (*verify_callback)(int, X509_STORE_CTX *)); 51 | int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); 52 | int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, 53 | const char *CApath); 54 | long SSL_get_verify_result(const SSL *ssl); 55 | X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx); 56 | int X509_STORE_add_cert(X509_STORE *ctx, X509 *x); 57 | int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str); 58 | long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg); 59 | void SSL_CTX_free(SSL_CTX *a); 60 | 61 | SSL *SSL_new(SSL_CTX *ctx); 62 | void SSL_free(SSL *ssl); 63 | void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio); 64 | long SSL_ctrl(SSL *ssl, int cmd, long larg, void *parg); 65 | _STACK *SSL_get_peer_cert_chain(const SSL *s); 66 | 67 | SSL_SESSION *SSL_get1_session(const SSL *ssl); 68 | int SSL_set_session(SSL *ssl, SSL_SESSION *session); 69 | void SSL_SESSION_free(SSL_SESSION *session); 70 | 71 | void SSL_set_connect_state(SSL *ssl); 72 | int SSL_do_handshake(SSL *ssl); 73 | int SSL_get_error(const SSL *ssl, int ret); 74 | const char *SSL_get_version(const SSL *ssl); 75 | 76 | int SSL_read(SSL *ssl, void *buf, int num); 77 | int SSL_write(SSL *ssl, const void *buf, int num); 78 | int SSL_pending(const SSL *ssl); 79 | 80 | int SSL_shutdown(SSL *ssl); 81 | """) 82 | 83 | if libcrypto_version_info < (1, 1): 84 | ffi.cdef(""" 85 | int sk_num(const _STACK *); 86 | X509 *sk_value(const _STACK *, int); 87 | 88 | int SSL_library_init(void); 89 | void OPENSSL_add_all_algorithms_noconf(void); 90 | 91 | SSL_METHOD *SSLv23_method(void); 92 | """) 93 | else: 94 | ffi.cdef(""" 95 | int OPENSSL_sk_num(const _STACK *); 96 | X509 *OPENSSL_sk_value(const _STACK *, int); 97 | 98 | SSL_METHOD *TLS_method(void); 99 | """) 100 | -------------------------------------------------------------------------------- /package_control/commands/list_available_libraries_command.py: -------------------------------------------------------------------------------- 1 | import html 2 | import re 3 | import threading 4 | from datetime import datetime 5 | 6 | import sublime 7 | import sublime_plugin 8 | 9 | from ..activity_indicator import ActivityIndicator 10 | from ..console_write import console_write 11 | from ..package_manager import PackageManager 12 | from ..show_error import show_message 13 | 14 | USE_QUICK_PANEL_ITEM = hasattr(sublime, "QuickPanelItem") 15 | 16 | 17 | class ListAvailableLibrariesCommand(sublime_plugin.ApplicationCommand): 18 | 19 | """ 20 | A command that presents the list of available packages and allows the 21 | user to pick one to install. 22 | """ 23 | 24 | def run(self): 25 | def show_quick_panel(): 26 | manager = PackageManager() 27 | 28 | with ActivityIndicator("Loading libraries...") as progress: 29 | libraries = manager.list_available_libraries() 30 | if not libraries: 31 | message = "There are no libraries available for installation" 32 | console_write(message) 33 | progress.finish(message) 34 | show_message( 35 | """ 36 | %s 37 | 38 | Please see https://packagecontrol.io/docs/troubleshooting for help 39 | """, 40 | message, 41 | ) 42 | return 43 | 44 | if USE_QUICK_PANEL_ITEM: 45 | self.show_quick_panel_st4(libraries.values()) 46 | else: 47 | self.show_quick_panel_st3(libraries.values()) 48 | 49 | threading.Thread(target=show_quick_panel).start() 50 | 51 | def show_quick_panel_st3(self, libraries): 52 | items = [ 53 | [info["name"] + " v" + info["releases"][0]["version"], info["description"]] 54 | for info in libraries 55 | ] 56 | 57 | def on_done(picked): 58 | if picked > -1: 59 | sublime.set_clipboard(items[picked][0].split(" ", 1)[0]) 60 | 61 | sublime.active_window().show_quick_panel( 62 | items, on_done, sublime.KEEP_OPEN_ON_FOCUS_LOST 63 | ) 64 | 65 | def show_quick_panel_st4(self, libraries): 66 | # TODO: display supported python versions 67 | 68 | items = [] 69 | for info in libraries: 70 | display_name = info["name"] + " v" + info["releases"][0]["version"] 71 | 72 | details = [html.escape(info["description"])] 73 | 74 | issues = html.escape(info["issues"]) 75 | issues_display = re.sub(r"^https?://", "", issues) 76 | if issues_display: 77 | details.append( 78 | 'report bug: {}'.format(issues, issues_display) 79 | ) 80 | 81 | try: 82 | date = info["releases"][0]["date"].split(" ", 1)[0] 83 | annotation = datetime.strptime(date, "%Y-%m-%d").strftime( 84 | "Updated on %a %b %d, %Y" 85 | ) 86 | except (IndexError, KeyError, ValueError): 87 | annotation = "" 88 | 89 | items.append(sublime.QuickPanelItem(display_name, details, annotation)) 90 | 91 | def on_done(picked): 92 | if picked > -1: 93 | sublime.set_clipboard(items[picked].trigger.split(" ", 1)[0]) 94 | 95 | sublime.active_window().show_quick_panel( 96 | items, on_done, sublime.KEEP_OPEN_ON_FOCUS_LOST 97 | ) 98 | -------------------------------------------------------------------------------- /package_control/http/persistent_handler.py: -------------------------------------------------------------------------------- 1 | import socket 2 | from urllib.error import URLError 3 | 4 | from ..console_write import console_write 5 | 6 | 7 | class PersistentHandler: 8 | connection = None 9 | use_count = 0 10 | 11 | def close(self): 12 | if self.connection: 13 | if self._debuglevel == 5: 14 | s = '' if self.use_count == 1 else 's' 15 | console_write( 16 | ''' 17 | Urllib %s Debug General 18 | Closing connection to %s on port %s after %s request%s 19 | ''', 20 | ( 21 | self.connection._debug_protocol, 22 | self.connection.host, 23 | self.connection.port, 24 | self.use_count, 25 | s 26 | ) 27 | ) 28 | self.connection.close() 29 | self.connection = None 30 | self.use_count = 0 31 | 32 | def do_open(self, http_class, req): 33 | # Large portions from Python 3.3 Lib/urllib/request.py and 34 | # Python 2.6 Lib/urllib2.py 35 | 36 | host = req.host 37 | 38 | if not host: 39 | raise URLError('no host given') 40 | 41 | if self.connection and self.connection.host != host: 42 | self.close() 43 | 44 | # Re-use the connection if possible 45 | self.use_count += 1 46 | if not self.connection: 47 | h = http_class(host, timeout=req.timeout) 48 | else: 49 | h = self.connection 50 | if self._debuglevel == 5: 51 | console_write( 52 | ''' 53 | Urllib %s Debug General 54 | Re-using connection to %s on port %s for request #%s 55 | ''', 56 | (h._debug_protocol, h.host, h.port, self.use_count) 57 | ) 58 | 59 | headers = dict(req.unredirected_hdrs) 60 | headers.update(dict((k, v) for k, v in req.headers.items() 61 | if k not in headers)) 62 | headers = dict((name.title(), val) for name, val in headers.items()) 63 | 64 | if req._tunnel_host and not self.connection: 65 | tunnel_headers = {} 66 | proxy_auth_hdr = "Proxy-Authorization" 67 | if proxy_auth_hdr in headers: 68 | tunnel_headers[proxy_auth_hdr] = headers[proxy_auth_hdr] 69 | del headers[proxy_auth_hdr] 70 | 71 | h.set_tunnel(req._tunnel_host, headers=tunnel_headers) 72 | 73 | try: 74 | h.request(req.get_method(), req.selector, req.data, headers) 75 | except socket.error as err: # timeout error 76 | h.close() 77 | raise URLError(err) 78 | else: 79 | r = h.getresponse() 80 | 81 | # Keep the connection around for re-use 82 | if r.is_keep_alive(): 83 | self.connection = h 84 | else: 85 | if self._debuglevel == 5: 86 | s = '' if self.use_count == 1 else 's' 87 | console_write( 88 | ''' 89 | Urllib %s Debug General 90 | Closing connection to %s on port %s after %s request%s 91 | ''', 92 | (h._debug_protocol, h.host, h.port, self.use_count, s) 93 | ) 94 | self.use_count = 0 95 | self.connection = None 96 | 97 | r.url = req.get_full_url() 98 | r.msg = r.reason 99 | return r 100 | -------------------------------------------------------------------------------- /package_control/providers/base_repository_provider.py: -------------------------------------------------------------------------------- 1 | class BaseRepositoryProvider: 2 | """ 3 | Base repository downloader that fetches package info 4 | 5 | This base class acts as interface to ensure all providers expose the same 6 | set of methods. All providers should therefore derive from this base class. 7 | 8 | The structure of the JSON a repository should contain is located in 9 | example-packages.json. 10 | 11 | :param repo_url: 12 | The URL of the package repository 13 | 14 | :param settings: 15 | A dict containing at least the following fields: 16 | `cache_length`, 17 | `debug`, 18 | `timeout`, 19 | `user_agent` 20 | Optional fields: 21 | `http_proxy`, 22 | `https_proxy`, 23 | `proxy_username`, 24 | `proxy_password`, 25 | `query_string_params` 26 | """ 27 | 28 | __slots__ = [ 29 | 'broken_libriaries', 30 | 'broken_packages', 31 | 'failed_sources', 32 | 'libraries', 33 | 'packages', 34 | 'repo_url', 35 | 'settings', 36 | ] 37 | 38 | def __init__(self, repo_url, settings): 39 | self.broken_libriaries = {} 40 | self.broken_packages = {} 41 | self.failed_sources = {} 42 | self.libraries = None 43 | self.packages = None 44 | self.repo_url = repo_url 45 | self.settings = settings 46 | 47 | @classmethod 48 | def match_url(cls, repo_url): 49 | """ 50 | Indicates if this provider can handle the provided repo_url 51 | """ 52 | 53 | return True 54 | 55 | def prefetch(self): 56 | """ 57 | Go out and perform HTTP operations, caching the result 58 | """ 59 | 60 | [name for name, info in self.get_packages()] 61 | 62 | def fetch(self): 63 | """ 64 | Retrieves and loads the JSON for other methods to use 65 | 66 | :raises: 67 | NotImplementedError: when called 68 | """ 69 | 70 | raise NotImplementedError() 71 | 72 | def get_broken_libraries(self): 73 | """ 74 | List of library names for libraries that are missing information 75 | 76 | :return: 77 | A generator of ("Library Name", Exception()) tuples 78 | """ 79 | 80 | return self.broken_libriaries.items() 81 | 82 | def get_broken_packages(self): 83 | """ 84 | List of package names for packages that are missing information 85 | 86 | :return: 87 | A generator of ("Package Name", Exception()) tuples 88 | """ 89 | 90 | return self.broken_packages.items() 91 | 92 | def get_failed_sources(self): 93 | """ 94 | List of any URLs that could not be accessed while accessing this repository 95 | 96 | :return: 97 | A generator of ("https://example.com", Exception()) tuples 98 | """ 99 | 100 | return self.failed_sources.items() 101 | 102 | def get_libraries(self, invalid_sources=None): 103 | """ 104 | For API-compatibility with RepositoryProvider 105 | """ 106 | 107 | return {}.items() 108 | 109 | def get_packages(self, invalid_sources=None): 110 | """ 111 | For API-compatibility with RepositoryProvider 112 | """ 113 | 114 | return {}.items() 115 | 116 | def get_sources(self): 117 | """ 118 | Return a list of current URLs that are directly referenced by the repo 119 | 120 | :return: 121 | A list of URLs 122 | """ 123 | 124 | return [self.repo_url] 125 | 126 | def get_renamed_packages(self): 127 | """For API-compatibility with RepositoryProvider""" 128 | 129 | return {} 130 | -------------------------------------------------------------------------------- /package_control/activity_indicator.py: -------------------------------------------------------------------------------- 1 | import sublime 2 | from threading import RLock 3 | 4 | 5 | class ActivityIndicator: 6 | """ 7 | An animated text-based indicator to show that some activity is in progress. 8 | 9 | The `target` argument should be a :class:`sublime.View` or :class:`sublime.Window`. 10 | The indicator will be shown in the status bar of that view or window. 11 | If `label` is provided, then it will be shown next to the animation. 12 | 13 | :class:`ActivityIndicator` can be used as a context manager. 14 | """ 15 | 16 | def __init__(self, label=None): 17 | self.label = label 18 | self.interval = 120 19 | self._lock = RLock() 20 | self._running = False 21 | self._ticks = 0 22 | self._view = None 23 | 24 | def __enter__(self): 25 | self.start() 26 | return self 27 | 28 | def __exit__(self, exc_type, exc_value, traceback): 29 | self.stop() 30 | 31 | def clear(self): 32 | if self._view: 33 | self._view.erase_status('_package_control') 34 | self._view = None 35 | 36 | def start(self): 37 | """ 38 | Start displaying the indicator and animate it. 39 | 40 | :raise RuntimeError: if the indicator is already running. 41 | """ 42 | 43 | with self._lock: 44 | if self._running: 45 | raise RuntimeError('Timer is already running') 46 | self._running = True 47 | self._ticks = 0 48 | self.update(self.render_indicator_text()) 49 | sublime.set_timeout(self.tick, self.interval) 50 | 51 | def stop(self): 52 | """ 53 | Stop displaying the indicator. 54 | 55 | If the indicator is not running, do nothing. 56 | """ 57 | 58 | with self._lock: 59 | if self._running: 60 | self._running = False 61 | self.clear() 62 | 63 | def finish(self, message): 64 | """ 65 | Stop the indicator and display a final status message 66 | 67 | :param message: 68 | The final status message to display 69 | """ 70 | 71 | def clear(): 72 | with self._lock: 73 | self.clear() 74 | 75 | if self._running: 76 | with self._lock: 77 | self._running = False 78 | self.update(message) 79 | 80 | sublime.set_timeout(clear, 4000) 81 | 82 | def tick(self): 83 | """ 84 | Invoke status bar update with specified interval. 85 | """ 86 | 87 | if self._running: 88 | self._ticks += 1 89 | self.update(self.render_indicator_text()) 90 | sublime.set_timeout(self.tick, self.interval) 91 | 92 | def update(self, text): 93 | """ 94 | Update activity indicator and label in status bar. 95 | 96 | :param text: 97 | The text to display in the status bar 98 | """ 99 | 100 | view = sublime.active_window().active_view() 101 | if view and view != self._view: 102 | if self._view: 103 | self._view.erase_status('_package_control') 104 | self._view = view 105 | if self._view: 106 | self._view.set_status('_package_control', text) 107 | 108 | def render_indicator_text(self): 109 | """ 110 | Render activity indicator and label. 111 | 112 | :returns: 113 | The activity indicator string to display in the status bar 114 | """ 115 | 116 | text = '⣷⣯⣟⡿⢿⣻⣽⣾'[self._ticks % 8] 117 | if self.label: 118 | text += " " + self.label 119 | return text 120 | 121 | def set_label(self, label): 122 | with self._lock: 123 | self.label = label 124 | -------------------------------------------------------------------------------- /package_control/http_cache.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | 4 | from . import sys_path 5 | 6 | 7 | class HttpCache: 8 | 9 | """ 10 | A data store for caching HTTP response data. 11 | """ 12 | 13 | def __init__(self, ttl): 14 | """ 15 | Constructs a new instance. 16 | 17 | :param ttl: 18 | The number of seconds a cache entry should be valid for 19 | """ 20 | self.ttl = float(ttl) 21 | self.base_path = os.path.join(sys_path.pc_cache_dir(), 'http_cache') 22 | os.makedirs(self.base_path, exist_ok=True) 23 | 24 | def age(self, key): 25 | """ 26 | Return time since last modification. 27 | 28 | :param key: 29 | The key to fetch the cache for 30 | """ 31 | try: 32 | cache_file = os.path.join(self.base_path, key) 33 | return time.time() - os.stat(cache_file).st_mtime 34 | except FileNotFoundError: 35 | return 2 ** 32 36 | 37 | def touch(self, key): 38 | """ 39 | Update modification time 40 | 41 | :param key: 42 | The key to fetch the cache for 43 | """ 44 | now = time.time() 45 | 46 | try: 47 | cache_file = os.path.join(self.base_path, key) 48 | os.utime(cache_file, (now, now)) 49 | except FileNotFoundError: 50 | pass 51 | try: 52 | cache_file = os.path.join(self.base_path, key + '.info') 53 | os.utime(cache_file, (now, now)) 54 | except FileNotFoundError: 55 | pass 56 | 57 | def prune(self): 58 | """ 59 | Removes all cache entries older than the TTL 60 | 61 | :param ttl: 62 | The number of seconds a cache entry should be valid for 63 | """ 64 | try: 65 | for filename in os.listdir(self.base_path): 66 | path = os.path.join(self.base_path, filename) 67 | # There should not be any folders in the cache dir, but we 68 | # ignore to prevent an exception 69 | if os.path.isdir(path): 70 | continue 71 | if os.stat(path).st_atime < time.time() - self.ttl: 72 | os.unlink(path) 73 | 74 | except FileNotFoundError: 75 | pass 76 | 77 | def get(self, key): 78 | """ 79 | Returns a cached value 80 | 81 | :param key: 82 | The key to fetch the cache for 83 | 84 | :return: 85 | The (binary) cached value, or False 86 | """ 87 | try: 88 | cache_file = os.path.join(self.base_path, key) 89 | 90 | # update filetime to prevent unmodified cache files 91 | # from being deleted, if they are frequently accessed. 92 | # NOTE: try to rely on OS updating access time (`os.stat(path).st_atime`) 93 | # os.utime(cache_file) 94 | 95 | with open(cache_file, 'rb') as fobj: 96 | return fobj.read() 97 | 98 | except FileNotFoundError: 99 | return False 100 | 101 | def has(self, key): 102 | cache_file = os.path.join(self.base_path, key) 103 | return os.path.exists(cache_file) 104 | 105 | def path(self, key): 106 | """ 107 | Returns the filesystem path to the key 108 | 109 | :param key: 110 | The key to get the path for 111 | 112 | :return: 113 | The absolute filesystem path to the cache file 114 | """ 115 | 116 | return os.path.join(self.base_path, key) 117 | 118 | def set(self, key, content): 119 | """ 120 | Saves a value in the cache 121 | 122 | :param key: 123 | The key to save the cache with 124 | 125 | :param content: 126 | The (binary) content to cache 127 | """ 128 | 129 | cache_file = os.path.join(self.base_path, key) 130 | with open(cache_file, 'wb') as f: 131 | f.write(content) 132 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_pkcs5.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import sys 5 | import hashlib 6 | import hmac 7 | import struct 8 | 9 | from ._asn1 import int_from_bytes, int_to_bytes 10 | from ._errors import pretty_message 11 | from ._types import type_name, byte_cls, int_types 12 | 13 | if sys.version_info < (3,): 14 | chr_cls = chr 15 | 16 | else: 17 | def chr_cls(num): 18 | return bytes([num]) 19 | 20 | 21 | __all__ = [ 22 | 'pbkdf2', 23 | ] 24 | 25 | 26 | def pbkdf2(hash_algorithm, password, salt, iterations, key_length): 27 | """ 28 | Implements PBKDF2 from PKCS#5 v2.2 in pure Python 29 | 30 | :param hash_algorithm: 31 | The string name of the hash algorithm to use: "md5", "sha1", "sha224", 32 | "sha256", "sha384", "sha512" 33 | 34 | :param password: 35 | A byte string of the password to use an input to the KDF 36 | 37 | :param salt: 38 | A cryptographic random byte string 39 | 40 | :param iterations: 41 | The numbers of iterations to use when deriving the key 42 | 43 | :param key_length: 44 | The length of the desired key in bytes 45 | 46 | :return: 47 | The derived key as a byte string 48 | """ 49 | 50 | if not isinstance(password, byte_cls): 51 | raise TypeError(pretty_message( 52 | ''' 53 | password must be a byte string, not %s 54 | ''', 55 | type_name(password) 56 | )) 57 | 58 | if not isinstance(salt, byte_cls): 59 | raise TypeError(pretty_message( 60 | ''' 61 | salt must be a byte string, not %s 62 | ''', 63 | type_name(salt) 64 | )) 65 | 66 | if not isinstance(iterations, int_types): 67 | raise TypeError(pretty_message( 68 | ''' 69 | iterations must be an integer, not %s 70 | ''', 71 | type_name(iterations) 72 | )) 73 | 74 | if iterations < 1: 75 | raise ValueError(pretty_message( 76 | ''' 77 | iterations must be greater than 0 - is %s 78 | ''', 79 | repr(iterations) 80 | )) 81 | 82 | if not isinstance(key_length, int_types): 83 | raise TypeError(pretty_message( 84 | ''' 85 | key_length must be an integer, not %s 86 | ''', 87 | type_name(key_length) 88 | )) 89 | 90 | if key_length < 1: 91 | raise ValueError(pretty_message( 92 | ''' 93 | key_length must be greater than 0 - is %s 94 | ''', 95 | repr(key_length) 96 | )) 97 | 98 | if hash_algorithm not in set(['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512']): 99 | raise ValueError(pretty_message( 100 | ''' 101 | hash_algorithm must be one of "md5", "sha1", "sha224", "sha256", 102 | "sha384", "sha512", not %s 103 | ''', 104 | repr(hash_algorithm) 105 | )) 106 | 107 | algo = getattr(hashlib, hash_algorithm) 108 | 109 | hash_length = { 110 | 'md5': 16, 111 | 'sha1': 20, 112 | 'sha224': 28, 113 | 'sha256': 32, 114 | 'sha384': 48, 115 | 'sha512': 64 116 | }[hash_algorithm] 117 | 118 | original_hmac = hmac.new(password, None, algo) 119 | 120 | block = 1 121 | output = b'' 122 | 123 | while len(output) < key_length: 124 | prf = original_hmac.copy() 125 | prf.update(salt + struct.pack(b'>I', block)) 126 | last = prf.digest() 127 | 128 | u = int_from_bytes(last) 129 | 130 | for _ in range(iterations-1): 131 | prf = original_hmac.copy() 132 | prf.update(last) 133 | last = prf.digest() 134 | u ^= int_from_bytes(last) 135 | 136 | output += int_to_bytes(u, width=hash_length) 137 | block += 1 138 | 139 | return output[0:key_length] 140 | 141 | 142 | pbkdf2.pure_python = True 143 | -------------------------------------------------------------------------------- /package_control/automatic_upgrader.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import datetime 4 | # To prevent import errors in thread with datetime 5 | import locale # noqa 6 | import time 7 | 8 | import sublime 9 | 10 | from . import sys_path 11 | from .activity_indicator import ActivityIndicator 12 | from .console_write import console_write 13 | from .package_tasks import PackageTaskRunner 14 | 15 | 16 | class AutomaticUpgrader: 17 | 18 | """ 19 | Automatically checks for updated packages and installs them. controlled 20 | by the `auto_upgrade`, `auto_upgrade_ignore`, and `auto_upgrade_frequency` 21 | settings. 22 | """ 23 | 24 | def __init__(self, manager): 25 | self.manager = manager 26 | self.last_run = 0 27 | self.last_version = 0 28 | self.next_run = 0 29 | self.current_version = int(sublime.version()) 30 | 31 | def run(self): 32 | self.load_last_run() 33 | 34 | if self.last_version != self.current_version and self.last_version != 0: 35 | console_write( 36 | ''' 37 | Detected Sublime Text update, looking for package updates 38 | ''' 39 | ) 40 | 41 | elif self.next_run > int(time.time()): 42 | last_run = datetime.datetime.fromtimestamp(self.last_run) 43 | next_run = datetime.datetime.fromtimestamp(self.next_run) 44 | date_format = '%Y-%m-%d %H:%M:%S' 45 | console_write( 46 | ''' 47 | Skipping automatic upgrade, last run at %s, next run at %s or after 48 | ''', 49 | (last_run.strftime(date_format), next_run.strftime(date_format)) 50 | ) 51 | return 52 | 53 | self.upgrade_packages() 54 | 55 | def load_last_run(self): 56 | """ 57 | Loads the last run time from disk into memory 58 | """ 59 | 60 | try: 61 | with open(os.path.join(sys_path.pc_cache_dir(), 'last_run.json')) as fobj: 62 | last_run_data = json.load(fobj) 63 | self.last_run = int(last_run_data['timestamp']) 64 | self.last_version = int(last_run_data['st_version']) 65 | except (FileNotFoundError, ValueError, TypeError): 66 | pass 67 | 68 | frequency = self.manager.settings.get('auto_upgrade_frequency') 69 | if frequency and self.last_run: 70 | self.next_run = int(self.last_run) + (frequency * 60 * 60) 71 | 72 | def save_last_run(self): 73 | """ 74 | Saves a record of when the last run was 75 | """ 76 | 77 | with open(os.path.join(sys_path.pc_cache_dir(), 'last_run.json'), 'w') as fobj: 78 | json.dump({ 79 | 'timestamp': int(time.time()), 80 | 'st_version': self.current_version 81 | }, fp=fobj) 82 | 83 | def upgrade_packages(self): 84 | """ 85 | Upgrades all packages that are not currently upgraded to the latest 86 | version. Also renames any installed packages to their new names. 87 | """ 88 | 89 | upgrader = PackageTaskRunner(self.manager) 90 | 91 | with ActivityIndicator('Searching updates...') as progress: 92 | # upgrade existing libraries 93 | required_libraries = upgrader.manager.find_required_libraries() 94 | missing_libraries = upgrader.manager.find_missing_libraries(required_libraries=required_libraries) 95 | upgrader.manager.install_libraries( 96 | libraries=required_libraries - missing_libraries, 97 | fail_early=False 98 | ) 99 | 100 | # run updater synchronously to delay any "You must restart ST" dialogues 101 | # Note: we are in PackageCleanup thread here 102 | completed = upgrader.upgrade_packages( 103 | ignore_packages=upgrader.manager.settings.get('auto_upgrade_ignore'), 104 | unattended=True, 105 | progress=progress 106 | ) 107 | if completed: 108 | self.save_last_run() 109 | -------------------------------------------------------------------------------- /package_control/deps/asn1crypto/csr.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | """ 4 | ASN.1 type classes for certificate signing requests (CSR). Exports the 5 | following items: 6 | 7 | - CertificationRequest() 8 | 9 | Other type classes are defined that help compose the types listed above. 10 | """ 11 | 12 | from __future__ import unicode_literals, division, absolute_import, print_function 13 | 14 | from .algos import SignedDigestAlgorithm 15 | from .core import ( 16 | Any, 17 | BitString, 18 | BMPString, 19 | Integer, 20 | ObjectIdentifier, 21 | OctetBitString, 22 | Sequence, 23 | SetOf, 24 | UTF8String 25 | ) 26 | from .keys import PublicKeyInfo 27 | from .x509 import DirectoryString, Extensions, Name 28 | 29 | 30 | # The structures in this file are taken from https://tools.ietf.org/html/rfc2986 31 | # and https://tools.ietf.org/html/rfc2985 32 | 33 | 34 | class Version(Integer): 35 | _map = { 36 | 0: 'v1', 37 | } 38 | 39 | 40 | class CSRAttributeType(ObjectIdentifier): 41 | _map = { 42 | '1.2.840.113549.1.9.7': 'challenge_password', 43 | '1.2.840.113549.1.9.9': 'extended_certificate_attributes', 44 | '1.2.840.113549.1.9.14': 'extension_request', 45 | # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wcce/a5eaae36-e9f3-4dc5-a687-bfa7115954f1 46 | '1.3.6.1.4.1.311.13.2.2': 'microsoft_enrollment_csp_provider', 47 | # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wcce/7c677cba-030d-48be-ba2b-01e407705f34 48 | '1.3.6.1.4.1.311.13.2.3': 'microsoft_os_version', 49 | # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wcce/64e5ff6d-c6dd-4578-92f7-b3d895f9b9c7 50 | '1.3.6.1.4.1.311.21.20': 'microsoft_request_client_info', 51 | } 52 | 53 | 54 | class SetOfDirectoryString(SetOf): 55 | _child_spec = DirectoryString 56 | 57 | 58 | class Attribute(Sequence): 59 | _fields = [ 60 | ('type', ObjectIdentifier), 61 | ('values', SetOf, {'spec': Any}), 62 | ] 63 | 64 | 65 | class SetOfAttributes(SetOf): 66 | _child_spec = Attribute 67 | 68 | 69 | class SetOfExtensions(SetOf): 70 | _child_spec = Extensions 71 | 72 | 73 | class MicrosoftEnrollmentCSProvider(Sequence): 74 | _fields = [ 75 | ('keyspec', Integer), 76 | ('cspname', BMPString), # cryptographic service provider name 77 | ('signature', BitString), 78 | ] 79 | 80 | 81 | class SetOfMicrosoftEnrollmentCSProvider(SetOf): 82 | _child_spec = MicrosoftEnrollmentCSProvider 83 | 84 | 85 | class MicrosoftRequestClientInfo(Sequence): 86 | _fields = [ 87 | ('clientid', Integer), 88 | ('machinename', UTF8String), 89 | ('username', UTF8String), 90 | ('processname', UTF8String), 91 | ] 92 | 93 | 94 | class SetOfMicrosoftRequestClientInfo(SetOf): 95 | _child_spec = MicrosoftRequestClientInfo 96 | 97 | 98 | class CRIAttribute(Sequence): 99 | _fields = [ 100 | ('type', CSRAttributeType), 101 | ('values', Any), 102 | ] 103 | 104 | _oid_pair = ('type', 'values') 105 | _oid_specs = { 106 | 'challenge_password': SetOfDirectoryString, 107 | 'extended_certificate_attributes': SetOfAttributes, 108 | 'extension_request': SetOfExtensions, 109 | 'microsoft_enrollment_csp_provider': SetOfMicrosoftEnrollmentCSProvider, 110 | 'microsoft_os_version': SetOfDirectoryString, 111 | 'microsoft_request_client_info': SetOfMicrosoftRequestClientInfo, 112 | } 113 | 114 | 115 | class CRIAttributes(SetOf): 116 | _child_spec = CRIAttribute 117 | 118 | 119 | class CertificationRequestInfo(Sequence): 120 | _fields = [ 121 | ('version', Version), 122 | ('subject', Name), 123 | ('subject_pk_info', PublicKeyInfo), 124 | ('attributes', CRIAttributes, {'implicit': 0, 'optional': True}), 125 | ] 126 | 127 | 128 | class CertificationRequest(Sequence): 129 | _fields = [ 130 | ('certification_request_info', CertificationRequestInfo), 131 | ('signature_algorithm', SignedDigestAlgorithm), 132 | ('signature', OctetBitString), 133 | ] 134 | -------------------------------------------------------------------------------- /Default.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Package Control: Add Channel", 4 | "command": "add_channel" 5 | }, 6 | { 7 | "caption": "Package Control: Add Repository", 8 | "command": "add_repository" 9 | }, 10 | { 11 | "caption": "Package Control: Advanced Disable Packages", 12 | "command": "disable_packages" 13 | }, 14 | { 15 | "caption": "Package Control: List Available Libraries", 16 | "command": "list_available_libraries" 17 | }, 18 | { 19 | "caption": "Package Control: Advanced Enable Packages", 20 | "command": "enable_packages" 21 | }, 22 | { 23 | "caption": "Package Control: Advanced Install Packages", 24 | "command": "install_packages" 25 | }, 26 | { 27 | "caption": "Package Control: Advanced Remove Packages", 28 | "command": "remove_packages" 29 | }, 30 | { 31 | "caption": "Package Control: Advanced Upgrade Packages", 32 | "command": "upgrade_packages" 33 | }, 34 | { 35 | "caption": "Package Control: Clear Cache Directory", 36 | "command": "clear_package_cache" 37 | }, 38 | { 39 | "caption": "Package Control: Create Package File", 40 | "command": "create_package" 41 | }, 42 | { 43 | "caption": "Package Control: Disable Package", 44 | "command": "disable_package" 45 | }, 46 | { 47 | "caption": "Package Control: Discover Packages", 48 | "command": "discover_packages" 49 | }, 50 | { 51 | "caption": "Package Control: Enable Package", 52 | "command": "enable_package" 53 | }, 54 | { 55 | "caption": "Package Control: Install Package", 56 | "command": "install_package" 57 | }, 58 | { 59 | "caption": "Package Control: List Packages", 60 | "command": "list_packages" 61 | }, 62 | { 63 | "caption": "Package Control: List Unmanaged Packages", 64 | "command": "list_unmanaged_packages" 65 | }, 66 | { 67 | "caption": "Package Control: Remove Channel", 68 | "command": "remove_channel" 69 | }, 70 | { 71 | "caption": "Package Control: Remove Package", 72 | "command": "remove_package" 73 | }, 74 | { 75 | "caption": "Package Control: Remove Repository", 76 | "command": "remove_repository" 77 | }, 78 | { 79 | "caption": "Package Control: Revert Built-in Package", 80 | "command": "revert_package" 81 | }, 82 | { 83 | "caption": "Package Control: Satisfy Libraries", 84 | "command": "satisfy_libraries" 85 | }, 86 | { 87 | "caption": "Package Control: Satisfy Packages", 88 | "command": "satisfy_packages" 89 | }, 90 | { 91 | "caption": "Package Control: Upgrade All Packages", 92 | "command": "upgrade_all_packages" 93 | }, 94 | { 95 | "caption": "Package Control: Upgrade Package", 96 | "command": "upgrade_package" 97 | }, 98 | { 99 | "caption": "Package Control: New Channel…", 100 | "command": "new_channel_json" 101 | }, 102 | { 103 | "caption": "Package Control: New Repository…", 104 | "command": "new_repository_json" 105 | }, 106 | { 107 | "caption": "Package Control: Enable Debug Mode", 108 | "command": "package_control_enable_debug_mode" 109 | }, 110 | { 111 | "caption": "Package Control: Disable Debug Mode", 112 | "command": "package_control_disable_debug_mode" 113 | }, 114 | { 115 | "caption": "Preferences: Package Control Settings", 116 | "command": "edit_settings", 117 | "args": { 118 | "base_file": "${packages}/Package Control/Package Control.sublime-settings", 119 | "default": "// See the left pane for the list of settings and valid values\n{\n\t$0\n}\n" 120 | } 121 | }, 122 | { 123 | "caption": "Package Control: User CA bundle", 124 | "command": "open_file", 125 | "args": { 126 | "file": "$packages/User/Package Control.user-ca-bundle", 127 | "semi_transient": true 128 | }, 129 | } 130 | ] 131 | -------------------------------------------------------------------------------- /messages/4.0.0.txt: -------------------------------------------------------------------------------- 1 | Version 4.0.0 Release Notes 2 | =========================== 3 | 4 | 5 | Major Changes 6 | ------------- 7 | 8 | - Requires at least ST3143 (1.0) 9 | 10 | - drops support for python 2.x 11 | 12 | - adds support for python 3.8 13 | 14 | - Package and library version scheme changed from SemVer to PEP440 15 | for better pre-release handling and compatibility with python packages. 16 | 17 | Note: Package versions should still follow SemVer like `..` 18 | 19 | - Dependencies are now called libraries. 20 | 21 | They are installed to Data/Libs as ordinary python packages. 22 | 23 | Existing managed dependencies are automatically converted. 24 | 25 | Can install python wheels (*.whl) 26 | 27 | - Channel/repository scheme v1.0 and v1.2 are no longer supported 28 | as they contain only packages for no longer supported ST2. 29 | 30 | - New channel/repository scheme v4.0.0 is introduced, 31 | which allows to specify supported `python_versions`. 32 | 33 | Parsing and installing "requirements.txt" is however not yet supported. 34 | 35 | For working examples checkout example-channel.json and example-repository.json 36 | from Package Control Github repository. 37 | 38 | 39 | Note for Package Devs 40 | --------------------- 41 | 42 | packagecontrol.io does not yet support the new 4.0.0 scheme 43 | and thus doesn't ship python 3.8 dependencies/libraries. 44 | 45 | Therefore do not upgrade repositories to 4.0.0 scheme, 46 | which are included in default channel. 47 | 48 | You can however create your own 4.0.0 repository and 49 | add it via 'Package Control: Add Repository'. 50 | 51 | Metadata for python 3.8 compatible libraries are maintained at 52 | 53 | https://github.com/packagecontrol/channel 54 | 55 | and shipped via 56 | 57 | https://packagecontrol.github.io/channel/channel_v4.json 58 | 59 | so all packages can already migrate to python 3.8 60 | 61 | 62 | New features include: 63 | --------------------- 64 | 65 | - support for python 3.8 dependencies (now called libraries) 66 | - add openssl 3.0 support via asn1crypto 1.5.1 and oscrypto 1.3.0 67 | - prune backups older than 14 days (#145) 68 | - provide all relevant operations via ApplicationCommands (#1071) 69 | + Advanced Disable Packages (disable_packages) 70 | + Advanced Enable Packages (enable_packages) 71 | + Advanced Install Packages (install_packages) 72 | + Advanced Upgrade Packages (upgrade_packages) 73 | + Advanced Remove Packages (remove_packages) 74 | - allow relative paths in channel.json and repository.json (#1329) 75 | - hide (auto-generated?) packages via `.hidden-sublime-package` file (#1429) 76 | - support for cooperate_packages (#1406, #1633) 77 | - IntelliSense support for for channel.json/repository.json via jsonschemas 78 | - support for asset based Github/Gitlab releases (#1484) 79 | 80 | 81 | Bug fixes include: 82 | ------------------ 83 | 84 | - abort package operation if backup fails (#1000) 85 | - fix long path support on Windows (#1020) 86 | - fix missing packages not being installed if an overriding unpacked package exists (#1155) 87 | - fix errors being displayed for git/hg tracked packages without remote (#1167) 88 | - fix not all git/hg tracked packages being upgraded 89 | - fix packages in auto_upgrade_ignore setting being renamed without upgrade (#1370) 90 | - fix corruption of installed_packages or ignored_packages settings 91 | - fix backup/restore of ST's "auto" color schemes and themes 92 | - fix manual package upgrades converting unmanaged packages to managed ones (#1272) 93 | - fix libraries not being upgraded by auto upgrader 94 | - fix prompt for ST restart before all operations are completed 95 | - fix SSL_CERT_FILE environment variable being ignored 96 | - fix repositories of channels without cache not being downloaded (#1354, #1601) 97 | - fix QuickPanelItem parse errors in URLs (#1580) 98 | - fix unavailable libraries being reported as successfully installed (#1605) 99 | - fix error message flooding 100 | - keep ingored_packages clean by removing non-existing packages 101 | 102 | ... 103 | 104 | The full list of addressed bugs can be found at: 105 | 106 | https://github.com/wbond/package_control/milestone/1 107 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_win/_secur32_cffi.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import sys 5 | 6 | from .._ffi import register_ffi 7 | from .._types import str_cls 8 | from ..errors import LibraryNotFoundError 9 | 10 | import cffi 11 | 12 | 13 | __all__ = [ 14 | 'get_error', 15 | 'secur32', 16 | ] 17 | 18 | 19 | ffi = cffi.FFI() 20 | if cffi.__version_info__ >= (0, 9): 21 | ffi.set_unicode(True) 22 | if sys.maxsize > 2 ** 32: 23 | ffi.cdef("typedef uint64_t ULONG_PTR;") 24 | else: 25 | ffi.cdef("typedef unsigned long ULONG_PTR;") 26 | ffi.cdef(""" 27 | typedef HANDLE HCERTSTORE; 28 | typedef unsigned int ALG_ID; 29 | typedef WCHAR SEC_WCHAR; 30 | typedef unsigned long SECURITY_STATUS; 31 | typedef void *LUID; 32 | typedef void *SEC_GET_KEY_FN; 33 | 34 | typedef struct _SecHandle { 35 | ULONG_PTR dwLower; 36 | ULONG_PTR dwUpper; 37 | } SecHandle; 38 | typedef SecHandle CredHandle; 39 | typedef SecHandle CtxtHandle; 40 | 41 | typedef struct _SCHANNEL_CRED { 42 | DWORD dwVersion; 43 | DWORD cCreds; 44 | void *paCred; 45 | HCERTSTORE hRootStore; 46 | DWORD cMappers; 47 | void **aphMappers; 48 | DWORD cSupportedAlgs; 49 | ALG_ID *palgSupportedAlgs; 50 | DWORD grbitEnabledProtocols; 51 | DWORD dwMinimumCipherStrength; 52 | DWORD dwMaximumCipherStrength; 53 | DWORD dwSessionLifespan; 54 | DWORD dwFlags; 55 | DWORD dwCredFormat; 56 | } SCHANNEL_CRED; 57 | 58 | typedef struct _TimeStamp { 59 | DWORD dwLowDateTime; 60 | DWORD dwHighDateTime; 61 | } TimeStamp; 62 | 63 | typedef struct _SecBuffer { 64 | ULONG cbBuffer; 65 | ULONG BufferType; 66 | BYTE *pvBuffer; 67 | } SecBuffer; 68 | 69 | typedef struct _SecBufferDesc { 70 | ULONG ulVersion; 71 | ULONG cBuffers; 72 | SecBuffer *pBuffers; 73 | } SecBufferDesc; 74 | 75 | typedef struct _SecPkgContext_StreamSizes { 76 | ULONG cbHeader; 77 | ULONG cbTrailer; 78 | ULONG cbMaximumMessage; 79 | ULONG cBuffers; 80 | ULONG cbBlockSize; 81 | } SecPkgContext_StreamSizes; 82 | 83 | typedef struct _CERT_CONTEXT { 84 | DWORD dwCertEncodingType; 85 | BYTE *pbCertEncoded; 86 | DWORD cbCertEncoded; 87 | void *pCertInfo; 88 | HCERTSTORE hCertStore; 89 | } CERT_CONTEXT; 90 | 91 | typedef struct _SecPkgContext_ConnectionInfo { 92 | DWORD dwProtocol; 93 | ALG_ID aiCipher; 94 | DWORD dwCipherStrength; 95 | ALG_ID aiHash; 96 | DWORD dwHashStrength; 97 | ALG_ID aiExch; 98 | DWORD dwExchStrength; 99 | } SecPkgContext_ConnectionInfo; 100 | 101 | SECURITY_STATUS AcquireCredentialsHandleW(SEC_WCHAR *pszPrincipal, SEC_WCHAR *pszPackage, ULONG fCredentialUse, 102 | LUID *pvLogonID, void *pAuthData, SEC_GET_KEY_FN pGetKeyFn, void *pvGetKeyArgument, 103 | CredHandle *phCredential, TimeStamp *ptsExpiry); 104 | SECURITY_STATUS FreeCredentialsHandle(CredHandle *phCredential); 105 | SECURITY_STATUS InitializeSecurityContextW(CredHandle *phCredential, CtxtHandle *phContext, 106 | SEC_WCHAR *pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep, 107 | SecBufferDesc *pInput, ULONG Reserved2, CtxtHandle *phNewContext, SecBufferDesc *pOutput, 108 | ULONG *pfContextAttr, TimeStamp *ptsExpiry); 109 | SECURITY_STATUS FreeContextBuffer(void *pvContextBuffer); 110 | SECURITY_STATUS ApplyControlToken(CtxtHandle *phContext, SecBufferDesc *pInput); 111 | SECURITY_STATUS DeleteSecurityContext(CtxtHandle *phContext); 112 | SECURITY_STATUS QueryContextAttributesW(CtxtHandle *phContext, ULONG ulAttribute, void *pBuffer); 113 | SECURITY_STATUS EncryptMessage(CtxtHandle *phContext, ULONG fQOP, SecBufferDesc *pMessage, ULONG MessageSeqNo); 114 | SECURITY_STATUS DecryptMessage(CtxtHandle *phContext, SecBufferDesc *pMessage, ULONG MessageSeqNo, ULONG *pfQOP); 115 | """) 116 | 117 | 118 | try: 119 | secur32 = ffi.dlopen('secur32.dll') 120 | register_ffi(secur32, ffi) 121 | 122 | except (OSError) as e: 123 | if str_cls(e).find('cannot load library') != -1: 124 | raise LibraryNotFoundError('secur32.dll could not be found') 125 | raise 126 | 127 | 128 | def get_error(): 129 | return ffi.getwinerror() 130 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_linux_bsd/trust_list.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | import os 5 | 6 | from .._asn1 import Certificate, TrustedCertificate, unarmor 7 | from .._errors import pretty_message 8 | 9 | 10 | __all__ = [ 11 | 'extract_from_system', 12 | 'system_path', 13 | ] 14 | 15 | 16 | def system_path(): 17 | """ 18 | Tries to find a CA certs bundle in common locations 19 | 20 | :raises: 21 | OSError - when no valid CA certs bundle was found on the filesystem 22 | 23 | :return: 24 | The full filesystem path to a CA certs bundle file 25 | """ 26 | 27 | ca_path = None 28 | 29 | # Common CA cert paths 30 | paths = [ 31 | '/usr/lib/ssl/certs/ca-certificates.crt', 32 | '/etc/ssl/certs/ca-certificates.crt', 33 | '/etc/ssl/certs/ca-bundle.crt', 34 | '/etc/pki/tls/certs/ca-bundle.crt', 35 | '/etc/ssl/ca-bundle.pem', 36 | '/usr/local/share/certs/ca-root-nss.crt', 37 | '/etc/ssl/cert.pem' 38 | ] 39 | 40 | # First try SSL_CERT_FILE 41 | if 'SSL_CERT_FILE' in os.environ: 42 | paths.insert(0, os.environ['SSL_CERT_FILE']) 43 | 44 | for path in paths: 45 | if os.path.exists(path) and os.path.getsize(path) > 0: 46 | ca_path = path 47 | break 48 | 49 | if not ca_path: 50 | raise OSError(pretty_message( 51 | ''' 52 | Unable to find a CA certs bundle in common locations - try 53 | setting the SSL_CERT_FILE environmental variable 54 | ''' 55 | )) 56 | 57 | return ca_path 58 | 59 | 60 | def extract_from_system(cert_callback=None, callback_only_on_failure=False): 61 | """ 62 | Extracts trusted CA certs from the system CA cert bundle 63 | 64 | :param cert_callback: 65 | A callback that is called once for each certificate in the trust store. 66 | It should accept two parameters: an asn1crypto.x509.Certificate object, 67 | and a reason. The reason will be None if the certificate is being 68 | exported, otherwise it will be a unicode string of the reason it won't. 69 | 70 | :param callback_only_on_failure: 71 | A boolean - if the callback should only be called when a certificate is 72 | not exported. 73 | 74 | :return: 75 | A list of 3-element tuples: 76 | - 0: a byte string of a DER-encoded certificate 77 | - 1: a set of unicode strings that are OIDs of purposes to trust the 78 | certificate for 79 | - 2: a set of unicode strings that are OIDs of purposes to reject the 80 | certificate for 81 | """ 82 | 83 | all_purposes = '2.5.29.37.0' 84 | ca_path = system_path() 85 | 86 | output = [] 87 | with open(ca_path, 'rb') as f: 88 | for armor_type, _, cert_bytes in unarmor(f.read(), multiple=True): 89 | # Without more info, a certificate is trusted for all purposes 90 | if armor_type == 'CERTIFICATE': 91 | if cert_callback: 92 | cert_callback(Certificate.load(cert_bytes), None) 93 | output.append((cert_bytes, set(), set())) 94 | 95 | # The OpenSSL TRUSTED CERTIFICATE construct adds OIDs for trusted 96 | # and rejected purposes, so we extract that info. 97 | elif armor_type == 'TRUSTED CERTIFICATE': 98 | cert, aux = TrustedCertificate.load(cert_bytes) 99 | reject_all = False 100 | trust_oids = set() 101 | reject_oids = set() 102 | for purpose in aux['trust']: 103 | if purpose.dotted == all_purposes: 104 | trust_oids = set([purpose.dotted]) 105 | break 106 | trust_oids.add(purpose.dotted) 107 | for purpose in aux['reject']: 108 | if purpose.dotted == all_purposes: 109 | reject_all = True 110 | break 111 | reject_oids.add(purpose.dotted) 112 | if reject_all: 113 | if cert_callback: 114 | cert_callback(cert, 'explicitly distrusted') 115 | continue 116 | if cert_callback and not callback_only_on_failure: 117 | cert_callback(cert, None) 118 | output.append((cert.dump(), trust_oids, reject_oids)) 119 | 120 | return output 121 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_openssl/_libcrypto.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .. import ffi 5 | from .._ffi import buffer_from_bytes, byte_string_from_buffer, null 6 | from .._types import str_cls 7 | 8 | if ffi() == 'cffi': 9 | from ._libcrypto_cffi import ( 10 | libcrypto, 11 | version as libcrypto_version, 12 | version_info as libcrypto_version_info 13 | ) 14 | else: 15 | from ._libcrypto_ctypes import ( 16 | libcrypto, 17 | version as libcrypto_version, 18 | version_info as libcrypto_version_info 19 | ) 20 | 21 | 22 | __all__ = [ 23 | 'handle_openssl_error', 24 | 'libcrypto', 25 | 'libcrypto_legacy_support', 26 | 'libcrypto_version', 27 | 'libcrypto_version_info', 28 | 'LibcryptoConst', 29 | 'peek_openssl_error', 30 | ] 31 | 32 | 33 | _encoding = 'utf-8' 34 | _fallback_encodings = ['utf-8', 'cp1252'] 35 | 36 | 37 | if libcrypto_version_info < (1, 1): 38 | libcrypto.ERR_load_crypto_strings() 39 | libcrypto.OPENSSL_config(null()) 40 | 41 | 42 | # This enables legacy algorithms in OpenSSL 3.0, such as RC2, etc 43 | # which are used by various tests and some old protocols and things 44 | # like PKCS12 45 | libcrypto_legacy_support = True 46 | if libcrypto_version_info >= (3, ): 47 | 48 | libcrypto.OSSL_PROVIDER_load(null(), "legacy".encode("ascii")) 49 | libcrypto.OSSL_PROVIDER_load(null(), "default".encode("ascii")) 50 | 51 | if libcrypto.OSSL_PROVIDER_available(null(), "legacy".encode("ascii")) == 0: 52 | libcrypto_legacy_support = False 53 | 54 | 55 | def _try_decode(value): 56 | 57 | try: 58 | return str_cls(value, _encoding) 59 | 60 | # If the "correct" encoding did not work, try some defaults, and then just 61 | # obliterate characters that we can't seen to decode properly 62 | except (UnicodeDecodeError): 63 | for encoding in _fallback_encodings: 64 | try: 65 | return str_cls(value, encoding, errors='strict') 66 | except (UnicodeDecodeError): 67 | pass 68 | 69 | return str_cls(value, errors='replace') 70 | 71 | 72 | def handle_openssl_error(result, exception_class=None): 73 | """ 74 | Checks if an error occurred, and if so throws an OSError containing the 75 | last OpenSSL error message 76 | 77 | :param result: 78 | An integer result code - 1 or greater indicates success 79 | 80 | :param exception_class: 81 | The exception class to use for the exception if an error occurred 82 | 83 | :raises: 84 | OSError - when an OpenSSL error occurs 85 | """ 86 | 87 | if result > 0: 88 | return 89 | 90 | if exception_class is None: 91 | exception_class = OSError 92 | 93 | error_num = libcrypto.ERR_get_error() 94 | buffer = buffer_from_bytes(120) 95 | libcrypto.ERR_error_string(error_num, buffer) 96 | 97 | # Since we are dealing with a string, it is NULL terminated 98 | error_string = byte_string_from_buffer(buffer) 99 | 100 | raise exception_class(_try_decode(error_string)) 101 | 102 | 103 | def peek_openssl_error(): 104 | """ 105 | Peeks into the error stack and pulls out the lib, func and reason 106 | 107 | :return: 108 | A three-element tuple of integers (lib, func, reason) 109 | """ 110 | 111 | error = libcrypto.ERR_peek_error() 112 | if libcrypto_version_info < (3, 0): 113 | lib = int((error >> 24) & 0xff) 114 | func = int((error >> 12) & 0xfff) 115 | reason = int(error & 0xfff) 116 | else: 117 | lib = int((error >> 23) & 0xff) 118 | # OpenSSL 3.0 removed ERR_GET_FUNC() 119 | func = 0 120 | reason = int(error & 0x7fffff) 121 | 122 | return (lib, func, reason) 123 | 124 | 125 | class LibcryptoConst(): 126 | EVP_CTRL_SET_RC2_KEY_BITS = 3 127 | 128 | SSLEAY_VERSION = 0 129 | 130 | RSA_PKCS1_PADDING = 1 131 | RSA_NO_PADDING = 3 132 | RSA_PKCS1_OAEP_PADDING = 4 133 | 134 | # OpenSSL 0.9.x 135 | EVP_MD_CTX_FLAG_PSS_MDLEN = -1 136 | 137 | # OpenSSL 1.x.x 138 | EVP_PKEY_CTRL_RSA_PADDING = 0x1001 139 | RSA_PKCS1_PSS_PADDING = 6 140 | EVP_PKEY_CTRL_RSA_PSS_SALTLEN = 0x1002 141 | EVP_PKEY_RSA = 6 142 | EVP_PKEY_OP_SIGN = 1 << 3 143 | EVP_PKEY_OP_VERIFY = 1 << 4 144 | 145 | NID_X9_62_prime256v1 = 415 146 | NID_secp384r1 = 715 147 | NID_secp521r1 = 716 148 | 149 | OPENSSL_EC_NAMED_CURVE = 1 150 | 151 | DH_GENERATOR_2 = 2 152 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_win/_secur32.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .. import ffi 5 | from ._decode import _try_decode 6 | from ..errors import TLSError 7 | from .._types import str_cls 8 | 9 | if ffi() == 'cffi': 10 | from ._secur32_cffi import secur32, get_error 11 | else: 12 | from ._secur32_ctypes import secur32, get_error 13 | 14 | 15 | __all__ = [ 16 | 'handle_error', 17 | 'secur32', 18 | 'Secur32Const', 19 | ] 20 | 21 | 22 | def handle_error(result, exception_class=None): 23 | """ 24 | Extracts the last Windows error message into a python unicode string 25 | 26 | :param result: 27 | A function result, 0 or None indicates failure 28 | 29 | :param exception_class: 30 | The exception class to use for the exception if an error occurred 31 | 32 | :return: 33 | A unicode string error message 34 | """ 35 | 36 | if result == 0: 37 | return 38 | 39 | if result == Secur32Const.SEC_E_OUT_OF_SEQUENCE: 40 | raise TLSError('A packet was received out of order') 41 | 42 | if result == Secur32Const.SEC_E_MESSAGE_ALTERED: 43 | raise TLSError('A packet was received altered') 44 | 45 | if result == Secur32Const.SEC_E_CONTEXT_EXPIRED: 46 | raise TLSError('The TLS session expired') 47 | 48 | _, error_string = get_error() 49 | 50 | if not isinstance(error_string, str_cls): 51 | error_string = _try_decode(error_string) 52 | 53 | if exception_class is None: 54 | exception_class = OSError 55 | 56 | raise exception_class(('SECURITY_STATUS error 0x%0.2X: ' % result) + error_string) 57 | 58 | 59 | class Secur32Const(): 60 | SCHANNEL_CRED_VERSION = 4 61 | 62 | SECPKG_CRED_OUTBOUND = 0x00000002 63 | UNISP_NAME = "Microsoft Unified Security Protocol Provider" 64 | 65 | SCH_CRED_MANUAL_CRED_VALIDATION = 0x00000008 66 | SCH_CRED_AUTO_CRED_VALIDATION = 0x00000020 67 | SCH_USE_STRONG_CRYPTO = 0x00400000 68 | SCH_CRED_NO_DEFAULT_CREDS = 0x00000010 69 | 70 | SECBUFFER_VERSION = 0 71 | 72 | SEC_E_OK = 0x00000000 73 | SEC_I_CONTINUE_NEEDED = 0x00090312 74 | SEC_I_CONTEXT_EXPIRED = 0x00090317 75 | SEC_I_RENEGOTIATE = 0x00090321 76 | SEC_E_INCOMPLETE_MESSAGE = 0x80090318 77 | SEC_E_INVALID_TOKEN = 0x80090308 78 | SEC_E_OUT_OF_SEQUENCE = 0x8009031 79 | SEC_E_MESSAGE_ALTERED = 0x8009030F 80 | SEC_E_CONTEXT_EXPIRED = 0x80090317 81 | SEC_E_INVALID_PARAMETER = 0x8009035D 82 | 83 | SEC_E_WRONG_PRINCIPAL = 0x80090322 # Domain name mismatch 84 | SEC_E_UNTRUSTED_ROOT = 0x80090325 85 | SEC_E_CERT_EXPIRED = 0x80090328 86 | SEC_E_ILLEGAL_MESSAGE = 0x80090326 # Handshake error 87 | SEC_E_INTERNAL_ERROR = 0x80090304 # Occurs when DH params are too small 88 | SEC_E_BUFFER_TOO_SMALL = 0x80090321 89 | SEC_I_INCOMPLETE_CREDENTIALS = 0x00090320 90 | 91 | ISC_REQ_REPLAY_DETECT = 4 92 | ISC_REQ_SEQUENCE_DETECT = 8 93 | ISC_REQ_CONFIDENTIALITY = 16 94 | ISC_REQ_ALLOCATE_MEMORY = 256 95 | ISC_REQ_INTEGRITY = 65536 96 | ISC_REQ_STREAM = 0x00008000 97 | ISC_REQ_USE_SUPPLIED_CREDS = 0x00000080 98 | 99 | ISC_RET_REPLAY_DETECT = 4 100 | ISC_RET_SEQUENCE_DETECT = 8 101 | ISC_RET_CONFIDENTIALITY = 16 102 | ISC_RET_ALLOCATED_MEMORY = 256 103 | ISC_RET_INTEGRITY = 65536 104 | ISC_RET_STREAM = 0x00008000 105 | 106 | SECBUFFER_ALERT = 17 107 | SECBUFFER_STREAM_HEADER = 7 108 | SECBUFFER_STREAM_TRAILER = 6 109 | SECBUFFER_EXTRA = 5 110 | SECBUFFER_TOKEN = 2 111 | SECBUFFER_DATA = 1 112 | SECBUFFER_EMPTY = 0 113 | 114 | SECPKG_ATTR_STREAM_SIZES = 0x04 115 | SECPKG_ATTR_CONNECTION_INFO = 0x5A 116 | SECPKG_ATTR_REMOTE_CERT_CONTEXT = 0x53 117 | 118 | SP_PROT_TLS1_2_CLIENT = 0x800 119 | SP_PROT_TLS1_1_CLIENT = 0x200 120 | SP_PROT_TLS1_CLIENT = 0x80 121 | SP_PROT_SSL3_CLIENT = 0x20 122 | SP_PROT_SSL2_CLIENT = 0x8 123 | 124 | CALG_AES_256 = 0x00006610 125 | CALG_AES_128 = 0x0000660E 126 | CALG_3DES = 0x00006603 127 | CALG_RC4 = 0x00006801 128 | CALG_RC2 = 0x00006602 129 | CALG_DES = 0x00006601 130 | 131 | CALG_MD5 = 0x00008003 132 | CALG_SHA1 = 0x00008004 133 | CALG_SHA256 = 0x0000800C 134 | CALG_SHA384 = 0x0000800D 135 | CALG_SHA512 = 0x0000800E 136 | 137 | CALG_DH_SF = 0x0000AA01 138 | CALG_DH_EPHEM = 0x0000AA02 139 | CALG_ECDH = 0x0000AA05 140 | CALG_ECDHE = 0x0000AE06 141 | CALG_RSA_KEYX = 0x0000A400 142 | 143 | CALG_RSA_SIGN = 0x00002400 144 | CALG_ECDSA = 0x00002203 145 | CALG_DSS_SIGN = 0x00002200 146 | -------------------------------------------------------------------------------- /package_control/events.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | import sublime 4 | 5 | INSTALL = 'install' 6 | REMOVE = 'remove' 7 | PRE_UPGRADE = 'pre_upgrade' 8 | POST_UPGRADE = 'post_upgrade' 9 | 10 | # This ensures we don't run into issues calling the event tracking methods 11 | # from threads 12 | __lock = threading.Lock() 13 | __tracker = None 14 | 15 | 16 | def _tracker(): 17 | """ 18 | Return event tracker storage object 19 | 20 | Use an unsaved settings object to share events across plugin_hosts. 21 | """ 22 | 23 | global __tracker 24 | 25 | if not isinstance(__tracker, sublime.Settings): 26 | tracker = sublime.load_settings("Package Control Events") 27 | if tracker is None or tracker.settings_id == 0: 28 | return {} 29 | __tracker = tracker 30 | 31 | return __tracker 32 | 33 | 34 | def add(event_type, package, version): 35 | """ 36 | Add a version to the tracker with the version specified 37 | 38 | :param event_type: 39 | The type of the tracker event: install, pre_upgrade, post_upgrade or 40 | remove 41 | 42 | :param package: 43 | The package name 44 | 45 | :param version: 46 | The version of the package the event is for 47 | """ 48 | 49 | if event_type not in (INSTALL, PRE_UPGRADE, POST_UPGRADE, REMOVE): 50 | raise KeyError(repr(event_type)) 51 | 52 | with __lock: 53 | tracker = _tracker() 54 | if tracker: 55 | packages = tracker.get(event_type, {}) 56 | packages[package] = version 57 | tracker.set(event_type, packages) 58 | 59 | 60 | def clear(event_type, package, future=False): 61 | """ 62 | Clears an event from the tracker, possibly in the future. Future clears 63 | are useful for 'install' and 'post_upgrade' events since we don't have a 64 | natural event to clear the data on. Thus we set a timeout for 5 seconds in 65 | the future. 66 | 67 | :param event_type: 68 | The type of event to clear 69 | 70 | :param package: 71 | The name of the package to clear the event info for 72 | 73 | :param future: 74 | If the clear should happen in 5 seconds, instead of immediately 75 | """ 76 | 77 | if event_type not in (INSTALL, PRE_UPGRADE, POST_UPGRADE, REMOVE): 78 | raise KeyError(repr(event_type)) 79 | 80 | def do_clear(): 81 | with __lock: 82 | tracker = _tracker() 83 | if tracker: 84 | packages = tracker.get(event_type) 85 | if packages and package in packages: 86 | del packages[package] 87 | tracker.set(event_type, packages) 88 | 89 | if future: 90 | sublime.set_timeout(do_clear, 5000) 91 | else: 92 | do_clear() 93 | 94 | 95 | def install(name): 96 | """ 97 | Check if a package was just installed (in plugin_loaded()) 98 | 99 | :param name: 100 | The name of the package to check 101 | 102 | :return: 103 | A unicode string of the version just installed or 104 | False if not just installed 105 | """ 106 | 107 | with __lock: 108 | event = _tracker().get(INSTALL) or {} 109 | return event.get(name, False) 110 | 111 | 112 | def pre_upgrade(name): 113 | """ 114 | Check if a package is about to be upgraded (in plugin_unloaded()) 115 | 116 | :param name: 117 | The name of the package to check 118 | 119 | :return: 120 | A unicode string of the version being upgraded from or 121 | False if not being upgraded 122 | """ 123 | 124 | with __lock: 125 | event = _tracker().get(PRE_UPGRADE) or {} 126 | return event.get(name, False) 127 | 128 | 129 | def post_upgrade(name): 130 | """ 131 | Check if a package was just upgraded (in plugin_loaded()) 132 | 133 | :param name: 134 | The name of the package to check 135 | 136 | :return: 137 | A unicode string of the version upgraded to or 138 | False if not just upgraded 139 | """ 140 | 141 | with __lock: 142 | event = _tracker().get(POST_UPGRADE) or {} 143 | return event.get(name, False) 144 | 145 | 146 | def remove(name): 147 | """ 148 | Check if a package is about to be removed (in plugin_unloaded()) 149 | 150 | :param name: 151 | The name of the package to check 152 | 153 | :return: 154 | A unicode string of the version about to be removed or 155 | False if not being removed 156 | """ 157 | 158 | with __lock: 159 | event = _tracker().get(REMOVE) or {} 160 | return event.get(name, False) 161 | -------------------------------------------------------------------------------- /package_control/package_version.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | from .console_write import console_write 4 | from .pep440 import PEP440Version, PEP440InvalidVersionError 5 | 6 | 7 | class PackageVersion(PEP440Version): 8 | __slots__ = ["_str"] 9 | 10 | _date_time_regex = re.compile(r"^\d{4}\.\d{2}\.\d{2}(?:\.\d{2}\.\d{2}\.\d{2})?$") 11 | 12 | def __init__(self, ver): 13 | """ 14 | Initialize a ``PackageVersion`` instance. 15 | 16 | The initializer acts as compatibility layer to convert legacy version schemes 17 | into a ``PEP440Version``. 18 | 19 | If the version is based on a date, converts to 0.0.1+yyyy.mm.dd.hh.mm.ss. 20 | 21 | :param ver: 22 | A string, dict with 'version' key, or a SemVer object 23 | 24 | :raises: 25 | TypeError, if ver is not a ``str``. 26 | ValueError, if ver is no valid version string 27 | """ 28 | 29 | if not isinstance(ver, str): 30 | raise TypeError("{!r} is not a string".format(ver)) 31 | 32 | # Store original version string with `v` trimmed to maintain backward compatibility 33 | # with regards to not normalize it. 34 | # The one and only use case is to keep existing CI tests working without change. 35 | if ver[0] == 'v': 36 | self._str = ver[1:] 37 | else: 38 | self._str = ver 39 | 40 | # We prepend 0 to all date-based version numbers so that developers 41 | # may switch to explicit versioning from GitHub/GitLab/BitBucket 42 | # versioning based on commit dates. 43 | # 44 | # The resulting semver is alwass 0.0.1 with timestamp being used 45 | # as build number, so any explicitly choosen version (via tags) will 46 | # be greater, once a package moves from branch to tag based releases. 47 | # 48 | # The result looks like: 49 | # 0.0.1+2020.07.15.10.50.38 50 | match = self._date_time_regex.match(ver) 51 | if match: 52 | ver = "0.0.1+" + ver 53 | 54 | try: 55 | super().__init__(ver) 56 | except PEP440InvalidVersionError: 57 | # maybe semver with incompatible pre-release tag 58 | # if, so treat it as dev build with local version 59 | if "-" in ver: 60 | ver, pre = ver.split("-", 1) 61 | if ver and pre: 62 | super().__init__(ver + "-dev+" + pre) 63 | return 64 | raise 65 | 66 | def __str__(self): 67 | return self._str 68 | 69 | 70 | def version_match_prefix(version, filter_prefix): 71 | """ 72 | Create a SemVer for a given version, if it matches filter_prefix. 73 | 74 | :param version: 75 | The version string to match 76 | 77 | :param filter_prefix: 78 | The prefix to match versions against 79 | 80 | :returns: 81 | SemVer, if version is valid and matches given filter_prefix 82 | None, if version is invalid or doesn't match filter_prefix 83 | """ 84 | 85 | try: 86 | if filter_prefix: 87 | if version.startswith(filter_prefix): 88 | return PackageVersion(version[len(filter_prefix):]) 89 | else: 90 | return PackageVersion(version) 91 | except ValueError: 92 | pass 93 | return None 94 | 95 | 96 | def version_sort(sortable, *fields, **kwargs): 97 | """ 98 | Sorts a list that is a list of versions, or dicts with a 'version' key. 99 | Can also secondly sort by another field. 100 | 101 | :param sortable: 102 | The list to sort 103 | 104 | :param *fields: 105 | If sortable is a list of dicts, perform secondary sort via these fields, 106 | in order 107 | 108 | :param **kwargs: 109 | Keyword args to pass on to sorted() 110 | 111 | :return: 112 | A copy of sortable that is sorted according to SemVer rules 113 | """ 114 | 115 | def _version_sort_key(item): 116 | if isinstance(item, dict): 117 | if "version" not in item: 118 | raise TypeError("%s is not a package or library release" % item) 119 | result = PackageVersion(item["version"]) 120 | if fields: 121 | result = (result,) 122 | for field in fields: 123 | result += (item[field],) 124 | return result 125 | 126 | return PackageVersion(item) 127 | 128 | try: 129 | return sorted(sortable, key=_version_sort_key, **kwargs) 130 | except ValueError as e: 131 | console_write( 132 | """ 133 | Error sorting versions - %s 134 | """, 135 | e, 136 | ) 137 | return [] 138 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_mac/_security.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .. import ffi 5 | from .._ffi import null 6 | from ..errors import TLSDisconnectError, TLSGracefulDisconnectError 7 | 8 | if ffi() == 'cffi': 9 | from ._security_cffi import Security, version_info as osx_version_info 10 | from ._core_foundation_cffi import CoreFoundation, CFHelpers 11 | else: 12 | from ._security_ctypes import Security, version_info as osx_version_info 13 | from ._core_foundation_ctypes import CoreFoundation, CFHelpers 14 | 15 | 16 | __all__ = [ 17 | 'handle_sec_error', 18 | 'osx_version_info', 19 | 'Security', 20 | 'SecurityConst', 21 | ] 22 | 23 | 24 | def handle_sec_error(error, exception_class=None): 25 | """ 26 | Checks a Security OSStatus error code and throws an exception if there is an 27 | error to report 28 | 29 | :param error: 30 | An OSStatus 31 | 32 | :param exception_class: 33 | The exception class to use for the exception if an error occurred 34 | 35 | :raises: 36 | OSError - when the OSStatus contains an error 37 | """ 38 | 39 | if error == 0: 40 | return 41 | 42 | if error in set([SecurityConst.errSSLClosedNoNotify, SecurityConst.errSSLClosedAbort]): 43 | raise TLSDisconnectError('The remote end closed the connection') 44 | if error == SecurityConst.errSSLClosedGraceful: 45 | raise TLSGracefulDisconnectError('The remote end closed the connection') 46 | 47 | cf_error_string = Security.SecCopyErrorMessageString(error, null()) 48 | output = CFHelpers.cf_string_to_unicode(cf_error_string) 49 | CoreFoundation.CFRelease(cf_error_string) 50 | 51 | if output is None or output == '': 52 | output = 'OSStatus %s' % error 53 | 54 | if exception_class is None: 55 | exception_class = OSError 56 | 57 | raise exception_class(output) 58 | 59 | 60 | def _extract_policy_properties(value): 61 | properties_dict = Security.SecPolicyCopyProperties(value) 62 | return CFHelpers.cf_dictionary_to_dict(properties_dict) 63 | 64 | 65 | CFHelpers.register_native_mapping( 66 | Security.SecPolicyGetTypeID(), 67 | _extract_policy_properties 68 | ) 69 | 70 | 71 | class SecurityConst(): 72 | kSecTrustSettingsDomainUser = 0 73 | kSecTrustSettingsDomainAdmin = 1 74 | kSecTrustSettingsDomainSystem = 2 75 | 76 | kSecTrustResultProceed = 1 77 | kSecTrustResultUnspecified = 4 78 | kSecTrustOptionImplicitAnchors = 0x00000040 79 | 80 | kSecFormatOpenSSL = 1 81 | 82 | kSecItemTypePrivateKey = 1 83 | kSecItemTypePublicKey = 2 84 | 85 | kSSLSessionOptionBreakOnServerAuth = 0 86 | 87 | kSSLProtocol2 = 1 88 | kSSLProtocol3 = 2 89 | kTLSProtocol1 = 4 90 | kTLSProtocol11 = 7 91 | kTLSProtocol12 = 8 92 | 93 | kSSLClientSide = 1 94 | kSSLStreamType = 0 95 | 96 | errSSLProtocol = -9800 97 | errSSLWouldBlock = -9803 98 | errSSLClosedGraceful = -9805 99 | errSSLClosedNoNotify = -9816 100 | errSSLClosedAbort = -9806 101 | 102 | errSSLXCertChainInvalid = -9807 103 | errSSLCrypto = -9809 104 | errSSLInternal = -9810 105 | errSSLCertExpired = -9814 106 | errSSLCertNotYetValid = -9815 107 | errSSLUnknownRootCert = -9812 108 | errSSLNoRootCert = -9813 109 | errSSLHostNameMismatch = -9843 110 | errSSLPeerHandshakeFail = -9824 111 | errSSLPeerProtocolVersion = -9836 112 | errSSLPeerUserCancelled = -9839 113 | errSSLWeakPeerEphemeralDHKey = -9850 114 | errSSLServerAuthCompleted = -9841 115 | errSSLRecordOverflow = -9847 116 | 117 | CSSMERR_APPLETP_HOSTNAME_MISMATCH = -2147408896 118 | CSSMERR_TP_CERT_EXPIRED = -2147409654 119 | CSSMERR_TP_CERT_NOT_VALID_YET = -2147409653 120 | CSSMERR_TP_CERT_REVOKED = -2147409652 121 | CSSMERR_TP_NOT_TRUSTED = -2147409622 122 | CSSMERR_TP_CERT_SUSPENDED = -2147409651 123 | 124 | CSSM_CERT_X_509v3 = 0x00000004 125 | 126 | APPLE_TP_REVOCATION_CRL = b'*\x86H\x86\xf7cd\x01\x06' 127 | APPLE_TP_REVOCATION_OCSP = b'*\x86H\x86\xf7cd\x01\x07' 128 | 129 | CSSM_APPLE_TP_OCSP_OPTS_VERSION = 0 130 | CSSM_TP_ACTION_OCSP_DISABLE_NET = 0x00000004 131 | CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE = 0x00000008 132 | 133 | CSSM_APPLE_TP_CRL_OPTS_VERSION = 0 134 | 135 | errSecVerifyFailed = -67808 136 | errSecNoTrustSettings = -25263 137 | errSecItemNotFound = -25300 138 | errSecInvalidTrustSettings = -25262 139 | 140 | kSecPaddingNone = 0 141 | kSecPaddingPKCS1 = 1 142 | 143 | CSSM_KEYUSE_SIGN = 0x00000004 144 | CSSM_KEYUSE_VERIFY = 0x00000008 145 | 146 | CSSM_ALGID_DH = 2 147 | CSSM_ALGID_RSA = 42 148 | CSSM_ALGID_DSA = 43 149 | CSSM_ALGID_ECDSA = 73 150 | CSSM_KEYATTR_PERMANENT = 0x00000001 151 | CSSM_KEYATTR_EXTRACTABLE = 0x00000020 152 | -------------------------------------------------------------------------------- /package_control/deps/oscrypto/_win/_cng_cffi.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals, division, absolute_import, print_function 3 | 4 | from .._ffi import register_ffi 5 | from .._types import str_cls 6 | from ..errors import LibraryNotFoundError 7 | 8 | from cffi import FFI 9 | 10 | 11 | __all__ = [ 12 | 'bcrypt', 13 | ] 14 | 15 | 16 | ffi = FFI() 17 | ffi.cdef(""" 18 | typedef HANDLE BCRYPT_ALG_HANDLE; 19 | typedef HANDLE BCRYPT_KEY_HANDLE; 20 | typedef ULONG NTSTATUS; 21 | typedef unsigned char *PUCHAR; 22 | typedef unsigned char *PBYTE; 23 | 24 | 25 | typedef struct _BCRYPT_RSAKEY_BLOB { 26 | ULONG Magic; 27 | ULONG BitLength; 28 | ULONG cbPublicExp; 29 | ULONG cbModulus; 30 | ULONG cbPrime1; 31 | ULONG cbPrime2; 32 | } BCRYPT_RSAKEY_BLOB; 33 | 34 | typedef struct _BCRYPT_DSA_KEY_BLOB { 35 | ULONG dwMagic; 36 | ULONG cbKey; 37 | UCHAR Count[4]; 38 | UCHAR Seed[20]; 39 | UCHAR q[20]; 40 | } BCRYPT_DSA_KEY_BLOB; 41 | 42 | typedef struct _BCRYPT_DSA_KEY_BLOB_V2 { 43 | ULONG dwMagic; 44 | ULONG cbKey; 45 | INT hashAlgorithm; 46 | INT standardVersion; 47 | ULONG cbSeedLength; 48 | ULONG cbGroupSize; 49 | UCHAR Count[4]; 50 | } BCRYPT_DSA_KEY_BLOB_V2; 51 | 52 | typedef struct _BCRYPT_ECCKEY_BLOB { 53 | ULONG dwMagic; 54 | ULONG cbKey; 55 | } BCRYPT_ECCKEY_BLOB; 56 | 57 | typedef struct _BCRYPT_PKCS1_PADDING_INFO { 58 | LPCWSTR pszAlgId; 59 | } BCRYPT_PKCS1_PADDING_INFO; 60 | 61 | typedef struct _BCRYPT_PSS_PADDING_INFO { 62 | LPCWSTR pszAlgId; 63 | ULONG cbSalt; 64 | } BCRYPT_PSS_PADDING_INFO; 65 | 66 | typedef struct _BCRYPT_OAEP_PADDING_INFO { 67 | LPCWSTR pszAlgId; 68 | PUCHAR pbLabel; 69 | ULONG cbLabel; 70 | } BCRYPT_OAEP_PADDING_INFO; 71 | 72 | typedef struct _BCRYPT_KEY_DATA_BLOB_HEADER { 73 | ULONG dwMagic; 74 | ULONG dwVersion; 75 | ULONG cbKeyData; 76 | } BCRYPT_KEY_DATA_BLOB_HEADER; 77 | 78 | NTSTATUS BCryptOpenAlgorithmProvider(BCRYPT_ALG_HANDLE *phAlgorithm, LPCWSTR pszAlgId, LPCWSTR pszImplementation, 79 | DWORD dwFlags); 80 | NTSTATUS BCryptCloseAlgorithmProvider(BCRYPT_ALG_HANDLE hAlgorithm, DWORD dwFlags); 81 | NTSTATUS BCryptSetProperty(HANDLE hObject, LPCWSTR pszProperty, ULONG *pbInput, ULONG cbInput, ULONG dwFlags); 82 | 83 | NTSTATUS BCryptImportKeyPair(BCRYPT_ALG_HANDLE hAlgorithm, BCRYPT_KEY_HANDLE hImportKey, LPCWSTR pszBlobType, 84 | BCRYPT_KEY_HANDLE *phKey, PUCHAR pbInput, ULONG cbInput, ULONG dwFlags); 85 | NTSTATUS BCryptImportKey(BCRYPT_ALG_HANDLE hAlgorithm, BCRYPT_KEY_HANDLE hImportKey, LPCWSTR pszBlobType, 86 | BCRYPT_KEY_HANDLE *phKey, PUCHAR pbKeyObject, ULONG cbKeyObject, PUCHAR pbInput, ULONG cbInput, 87 | ULONG dwFlags); 88 | NTSTATUS BCryptDestroyKey(BCRYPT_KEY_HANDLE hKey); 89 | 90 | NTSTATUS BCryptVerifySignature(BCRYPT_KEY_HANDLE hKey, void *pPaddingInfo, PUCHAR pbHash, ULONG cbHash, 91 | PUCHAR pbSignature, ULONG cbSignature, ULONG dwFlags); 92 | NTSTATUS BCryptSignHash(BCRYPT_KEY_HANDLE hKey, void * pPaddingInfo, PBYTE pbInput, DWORD cbInput, PBYTE pbOutput, 93 | DWORD cbOutput, DWORD *pcbResult, ULONG dwFlags); 94 | 95 | NTSTATUS BCryptEncrypt(BCRYPT_KEY_HANDLE hKey, PUCHAR pbInput, ULONG cbInput, void *pPaddingInfo, PUCHAR pbIV, 96 | ULONG cbIV, PUCHAR pbOutput, ULONG cbOutput, ULONG *pcbResult, ULONG dwFlags); 97 | NTSTATUS BCryptDecrypt(BCRYPT_KEY_HANDLE hKey, PUCHAR pbInput, ULONG cbInput, void *pPaddingInfo, PUCHAR pbIV, 98 | ULONG cbIV, PUCHAR pbOutput, ULONG cbOutput, ULONG *pcbResult, ULONG dwFlags); 99 | 100 | NTSTATUS BCryptDeriveKeyPBKDF2(BCRYPT_ALG_HANDLE hPrf, PUCHAR pbPassword, ULONG cbPassword, PUCHAR pbSalt, 101 | ULONG cbSalt, ULONGLONG cIterations, PUCHAR pbDerivedKey, ULONG cbDerivedKey, ULONG dwFlags); 102 | 103 | NTSTATUS BCryptGenRandom(BCRYPT_ALG_HANDLE hAlgorithm, PUCHAR pbBuffer, ULONG cbBuffer, ULONG dwFlags); 104 | 105 | NTSTATUS BCryptGenerateKeyPair(BCRYPT_ALG_HANDLE hAlgorithm, BCRYPT_KEY_HANDLE *phKey, ULONG dwLength, 106 | ULONG dwFlags); 107 | NTSTATUS BCryptFinalizeKeyPair(BCRYPT_KEY_HANDLE hKey, ULONG dwFlags); 108 | NTSTATUS BCryptExportKey(BCRYPT_KEY_HANDLE hKey, BCRYPT_KEY_HANDLE hExportKey, LPCWSTR pszBlobType, 109 | PUCHAR pbOutput, ULONG cbOutput, ULONG *pcbResult, ULONG dwFlags); 110 | """) 111 | 112 | 113 | try: 114 | bcrypt = ffi.dlopen('bcrypt.dll') 115 | register_ffi(bcrypt, ffi) 116 | 117 | except (OSError) as e: 118 | if str_cls(e).find('cannot load library') != -1: 119 | raise LibraryNotFoundError('bcrypt.dll could not be found - Windows XP and Server 2003 are not supported') 120 | raise 121 | --------------------------------------------------------------------------------