Ejemplo n.º 1
0
def upload(dists, repository, sign, identity, username, password, comment,
           sign_with, config_file, skip_existing, cert, client_cert):
    # Check that a nonsensical option wasn't given
    if not sign and identity:
        raise ValueError("sign must be given along with identity")

    dists = find_dists(dists)

    # Determine if the user has passed in pre-signed distributions
    signatures = dict(
        (os.path.basename(d), d) for d in dists if d.endswith(".asc"))
    uploads = [i for i in dists if not i.endswith(".asc")]

    config = utils.get_repository_from_config(config_file, repository)

    config["repository"] = utils.normalize_repository_url(config["repository"])

    print("Uploading distributions to {0}".format(config["repository"]))

    username = utils.get_username(username, config)
    password = utils.get_password(password, config)
    ca_cert = utils.get_cacert(cert, config)
    client_cert = utils.get_clientcert(client_cert, config)

    repository = Repository(config["repository"], username, password)
    repository.set_certificate_authority(ca_cert)
    repository.set_client_certificate(client_cert)

    for filename in uploads:
        package = PackageFile.from_filename(filename, comment)

        signed_name = package.signed_basefilename
        if signed_name in signatures:
            package.add_gpg_signature(signatures[signed_name], signed_name)
        elif sign:
            package.sign(sign_with, identity)

        resp = repository.upload(package)

        # Bug 92. If we get a redirect we should abort because something seems
        # funky. The behaviour is not well defined and redirects being issued
        # by PyPI should never happen in reality. This should catch malicious
        # redirects as well.
        if resp.is_redirect:
            raise exc.RedirectDetected(
                ('"{0}" attempted to redirect to "{1}" during upload.'
                 ' Aborting...').format(config["repository"],
                                        resp.headers["location"]))

        # Otherwise, raise an HTTPError based on the status code.
        if skip_upload(resp, skip_existing, package):
            print("  Skipping {0} because it appears to already exist".format(
                package.basefilename))
            continue

        resp.raise_for_status()

    # Bug 28. Try to silence a ResourceWarning by clearing the connection
    # pool.
    repository.close()
Ejemplo n.º 2
0
def register(package, repository, username, password, comment, config_file,
             cert, client_cert):
    config = utils.get_repository_from_config(config_file, repository)
    config["repository"] = utils.normalize_repository_url(
        config["repository"]
    )

    print("Registering package to {0}".format(config["repository"]))

    username = utils.get_username(username, config)
    password = utils.get_password(password, config)
    ca_cert = utils.get_cacert(cert, config)
    client_cert = utils.get_clientcert(client_cert, config)

    repository = Repository(config["repository"], username, password,
                            ca_cert, client_cert)

    if not os.path.exists(package):
        raise exc.PackageNotFound(
            '"{0}" does not exist on the file system.'.format(package)
        )

    resp = repository.register(PackageFile.from_filename(package, comment))
    repository.close()

    if resp.is_redirect:
        raise exc.RedirectDetected(
            ('"{0}" attempted to redirect to "{1}" during upload.'
             ' Aborting...').format(config["respository"],
                                    resp.headers["location"]))

    resp.raise_for_status()
Ejemplo n.º 3
0
def register(package, repository, username, password, comment, config_file,
             cert, client_cert):
    config = utils.get_repository_from_config(config_file, repository)
    config["repository"] = utils.normalize_repository_url(config["repository"])

    print("Registering package to {0}".format(config["repository"]))

    username = utils.get_username(username, config)
    password = utils.get_password(password, config)
    ca_cert = utils.get_cacert(cert, config)
    client_cert = utils.get_clientcert(client_cert, config)

    repository = Repository(config["repository"], username, password)
    repository.set_certificate_authority(ca_cert)
    repository.set_client_certificate(client_cert)

    if not os.path.exists(package):
        raise exc.PackageNotFound(
            '"{0}" does not exist on the file system.'.format(package))

    resp = repository.register(PackageFile.from_filename(package, comment))
    repository.close()

    if resp.is_redirect:
        raise exc.RedirectDetected(
            ('"{0}" attempted to redirect to "{1}" during registration.'
             ' Aborting...').format(config["repository"],
                                    resp.headers["location"]))

    resp.raise_for_status()
Ejemplo n.º 4
0
def test_get_username_and_password_keyring_overrides_prompt(monkeypatch):
    import collections
    Credential = collections.namedtuple('Credential', 'username password')

    class MockKeyring:
        @staticmethod
        def get_credential(system, user):
            return Credential(
                'real_user',
                'real_user@{system} sekure pa55word'.format(**locals())
            )

        @staticmethod
        def get_password(system, user):
            cred = MockKeyring.get_credential(system, user)
            if user != cred.username:
                raise RuntimeError("unexpected username")
            return cred.password

    monkeypatch.setitem(sys.modules, 'keyring', MockKeyring)

    user = utils.get_username('system', None, {})
    assert user == 'real_user'
    pw = utils.get_password('system', user, None, {})
    assert pw == 'real_user@system sekure pa55word'
Ejemplo n.º 5
0
def test_get_username_and_password_keyring_overrides_prompt(monkeypatch):
    import collections
    Credential = collections.namedtuple('Credential', 'username password')

    class MockKeyring:
        @staticmethod
        def get_credential(system, user):
            return Credential(
                'real_user',
                'real_user@{system} sekure pa55word'.format(**locals())
            )

        @staticmethod
        def get_password(system, user):
            cred = MockKeyring.get_credential(system, user)
            if user != cred.username:
                raise RuntimeError("unexpected username")
            return cred.password

    monkeypatch.setitem(sys.modules, 'keyring', MockKeyring)

    user = utils.get_username('system', None, {})
    assert user == 'real_user'
    pw = utils.get_password('system', user, None, {})
    assert pw == 'real_user@system sekure pa55word'
Ejemplo n.º 6
0
def upload(dists, repository, sign, identity, username, password, comment,
           sign_with, config_file, skip_existing):
    # Check that a nonsensical option wasn't given
    if not sign and identity:
        raise ValueError("sign must be given along with identity")

    dists = find_dists(dists)

    # Determine if the user has passed in pre-signed distributions
    signatures = dict(
        (os.path.basename(d), d) for d in dists if d.endswith(".asc")
    )
    uploads = [i for i in dists if not i.endswith(".asc")]

    config = utils.get_repository_from_config(config_file, repository)

    config["repository"] = utils.normalize_repository_url(
        config["repository"]
    )

    print("Uploading distributions to {0}".format(config["repository"]))

    username = utils.get_username(username, config)
    password = utils.get_password(password, config)

    repository = Repository(config["repository"], username, password)

    for filename in uploads:
        package = PackageFile.from_filename(filename, comment)

        signed_name = package.signed_basefilename
        if signed_name in signatures:
            package.add_gpg_signature(signatures[signed_name], signed_name)
        elif sign:
            package.sign(sign_with, identity)

        resp = repository.upload(package)

        # Bug 92. If we get a redirect we should abort because something seems
        # funky. The behaviour is not well defined and redirects being issued
        # by PyPI should never happen in reality. This should catch malicious
        # redirects as well.
        if resp.is_redirect:
            raise exc.RedirectDetected(
                ('"{0}" attempted to redirect to "{1}" during upload.'
                 ' Aborting...').format(config["repository"],
                                        resp.headers["location"]))

        # Otherwise, raise an HTTPError based on the status code.
        if skip_upload(resp, skip_existing, package):
            print("  Skipping {0} because it appears to already exist".format(
                package.basefilename))
            continue

        resp.raise_for_status()

    # Bug 28. Try to silence a ResourceWarning by clearing the connection
    # pool.
    repository.close()
Ejemplo n.º 7
0
 def _handle_authentication(self, username, password):
     self.username = utils.get_username(username, self.repository_config)
     self.password = utils.get_password(
         self.repository_config['repository'],
         self.username,
         password,
         self.repository_config,
     )
Ejemplo n.º 8
0
def test_get_password_keyring_overrides_prompt(monkeypatch):
    class MockKeyring:
        @staticmethod
        def get_password(system, user):
            return '{user}@{system} sekure pa55word'.format(**locals())

    monkeypatch.setitem(sys.modules, 'keyring', MockKeyring)

    pw = utils.get_password('system', 'user', None, {})
    assert pw == 'user@system sekure pa55word'
Ejemplo n.º 9
0
def test_get_password_keyring_overrides_prompt(monkeypatch):
    class MockKeyring:
        @staticmethod
        def get_password(system, user):
            return '{user}@{system} sekure pa55word'.format(**locals())

    monkeypatch.setitem(sys.modules, 'keyring', MockKeyring)

    pw = utils.get_password('system', 'user', None, {})
    assert pw == 'user@system sekure pa55word'
Ejemplo n.º 10
0
def test_get_password_keyring_defers_to_prompt(monkeypatch):
    monkeypatch.setattr(utils, 'password_prompt', lambda prompt: 'entered pw')

    class MockKeyring:
        @staticmethod
        def get_password(system, user):
            return

    monkeypatch.setitem(sys.modules, 'keyring', MockKeyring)

    pw = utils.get_password('system', 'user', None, {})
    assert pw == 'entered pw'
Ejemplo n.º 11
0
def test_get_password_keyring_defers_to_prompt(monkeypatch):
    monkeypatch.setattr(utils, 'password_prompt', lambda prompt: 'entered pw')

    class MockKeyring:
        @staticmethod
        def get_password(system, user):
            return

    monkeypatch.setitem(sys.modules, 'keyring', MockKeyring)

    pw = utils.get_password('system', 'user', None, {})
    assert pw == 'entered pw'
Ejemplo n.º 12
0
 def _handle_authentication(self, username, password):
     self.username = utils.get_username(
         self.repository_config['repository'],
         username,
         self.repository_config
     )
     self.password = utils.get_password(
         self.repository_config['repository'],
         self.username,
         password,
         self.repository_config,
     )
Ejemplo n.º 13
0
 def _handle_authentication(self, username, password, non_interactive):
     self.username = utils.get_username(
         self.repository_config['repository'],
         username,
         self.repository_config,
         non_interactive,
     )
     self.password = utils.get_password(
         self.repository_config['repository'],
         self.username,
         password,
         self.repository_config,
         non_interactive,
     )
Ejemplo n.º 14
0
def test_get_password_keyring_missing_non_interactive_aborts(
        entered_username, keyring_missing_get_credentials):
    with pytest.raises(exceptions.NonInteractive):
        utils.get_password('system', 'user', None, {}, True)
Ejemplo n.º 15
0
def upload(dists, repository, sign, identity, username, password, comment,
           sign_with, config_file, skip_existing, cert, client_cert,
           repository_url):
    # Check that a nonsensical option wasn't given
    if not sign and identity:
        raise ValueError("sign must be given along with identity")

    dists = find_dists(dists)

    # Determine if the user has passed in pre-signed distributions
    signatures = dict(
        (os.path.basename(d), d) for d in dists if d.endswith(".asc")
    )
    uploads = [i for i in dists if not i.endswith(".asc")]

    config = utils.get_repository_from_config(
        config_file,
        repository,
        repository_url,
    )

    config["repository"] = utils.normalize_repository_url(
        config["repository"]
    )

    print("Uploading distributions to {0}".format(config["repository"]))

    username = utils.get_username(username, config)
    password = utils.get_password(
        config["repository"], username, password, config,
    )
    ca_cert = utils.get_cacert(cert, config)
    client_cert = utils.get_clientcert(client_cert, config)

    repository = Repository(config["repository"], username, password)
    repository.set_certificate_authority(ca_cert)
    repository.set_client_certificate(client_cert)

    for filename in uploads:
        package = PackageFile.from_filename(filename, comment)
        skip_message = (
            "  Skipping {0} because it appears to already exist".format(
                package.basefilename)
        )

        # Note: The skip_existing check *needs* to be first, because otherwise
        #       we're going to generate extra HTTP requests against a hardcoded
        #       URL for no reason.
        if skip_existing and repository.package_is_uploaded(package):
            print(skip_message)
            continue

        signed_name = package.signed_basefilename
        if signed_name in signatures:
            package.add_gpg_signature(signatures[signed_name], signed_name)
        elif sign:
            package.sign(sign_with, identity)

        resp = repository.upload(package)

        # Bug 92. If we get a redirect we should abort because something seems
        # funky. The behaviour is not well defined and redirects being issued
        # by PyPI should never happen in reality. This should catch malicious
        # redirects as well.
        if resp.is_redirect:
            raise exc.RedirectDetected(
                ('"{0}" attempted to redirect to "{1}" during upload.'
                 ' Aborting...').format(config["repository"],
                                        resp.headers["location"]))

        if skip_upload(resp, skip_existing, package):
            print(skip_message)
            continue

        utils.check_status_code(resp)

    # Bug 28. Try to silence a ResourceWarning by clearing the connection
    # pool.
    repository.close()
Ejemplo n.º 16
0
def test_no_password_defers_to_prompt(monkeypatch):
    monkeypatch.setattr(utils, 'password_prompt', lambda prompt: 'entered pw')
    pw = utils.get_password('system', 'user', None, {'password': None})
    assert pw == 'entered pw'
Ejemplo n.º 17
0
def upload(dists, repository, sign, identity, username, password, comment,
           sign_with, config_file, skip_existing, cert, client_cert,
           repository_url):
    # Check that a nonsensical option wasn't given
    if not sign and identity:
        raise ValueError("sign must be given along with identity")

    dists = find_dists(dists)

    # Determine if the user has passed in pre-signed distributions
    signatures = dict(
        (os.path.basename(d), d) for d in dists if d.endswith(".asc")
    )
    uploads = [i for i in dists if not i.endswith(".asc")]

    config = utils.get_repository_from_config(
        config_file,
        repository,
        repository_url,
    )

    config["repository"] = utils.normalize_repository_url(
        config["repository"]
    )

    print("Uploading distributions to {0}".format(config["repository"]))

    if config["repository"].startswith((LEGACY_PYPI, LEGACY_TEST_PYPI)):
        raise exc.UploadToDeprecatedPyPIDetected(
            "You're trying to upload to the legacy PyPI site '{0}'. "
            "Uploading to those sites is deprecated. \n "
            "The new sites are pypi.org and test.pypi.org. Try using "
            "{1} (or {2}) to upload your packages instead. "
            "These are the default URLs for Twine now. \n More at "
            "https://packaging.python.org/guides/migrating-to-pypi-org/ "
            ".".format(
                config["repository"],
                utils.DEFAULT_REPOSITORY,
                utils.TEST_REPOSITORY
                )
            )

    username = utils.get_username(username, config)
    password = utils.get_password(
        config["repository"], username, password, config,
    )
    ca_cert = utils.get_cacert(cert, config)
    client_cert = utils.get_clientcert(client_cert, config)

    repository = Repository(config["repository"], username, password)
    repository.set_certificate_authority(ca_cert)
    repository.set_client_certificate(client_cert)

    for filename in uploads:
        package = PackageFile.from_filename(filename, comment)
        skip_message = (
            "  Skipping {0} because it appears to already exist".format(
                package.basefilename)
        )

        # Note: The skip_existing check *needs* to be first, because otherwise
        #       we're going to generate extra HTTP requests against a hardcoded
        #       URL for no reason.
        if skip_existing and repository.package_is_uploaded(package):
            print(skip_message)
            continue

        signed_name = package.signed_basefilename
        if signed_name in signatures:
            package.add_gpg_signature(signatures[signed_name], signed_name)
        elif sign:
            package.sign(sign_with, identity)

        resp = repository.upload(package)

        # Bug 92. If we get a redirect we should abort because something seems
        # funky. The behaviour is not well defined and redirects being issued
        # by PyPI should never happen in reality. This should catch malicious
        # redirects as well.
        if resp.is_redirect:
            raise exc.RedirectDetected(
                ('"{0}" attempted to redirect to "{1}" during upload.'
                 ' Aborting...').format(config["repository"],
                                        resp.headers["location"]))

        if skip_upload(resp, skip_existing, package):
            print(skip_message)
            continue

        utils.check_status_code(resp)

    # Bug 28. Try to silence a ResourceWarning by clearing the connection
    # pool.
    repository.close()
Ejemplo n.º 18
0
def upload(dists, repository, sign, identity, username, password, comment,
           sign_with):
    # Check that a nonsensical option wasn't given
    if not sign and identity:
        raise ValueError("sign must be given along with identity")

    # Determine if the user has passed in pre-signed distributions
    signatures = dict(
        (os.path.basename(d), d) for d in dists if d.endswith(".asc"))
    dists = [i for i in dists if not i.endswith(".asc")]

    # Get our config from ~/.pypirc
    try:
        config = get_config()[repository]
    except KeyError:
        raise KeyError(
            "Missing '{0}' section from the configuration file".format(
                repository, ), )

    parsed = urlparse(config["repository"])
    if parsed.netloc in ["pypi.python.org", "testpypi.python.org"]:
        config["repository"] = urlunparse(("https", ) + parsed[1:])

    print("Uploading distributions to {0}".format(config["repository"]))

    username = get_username(username, config)
    password = get_password(password, config)

    session = requests.session()

    uploads = find_dists(dists)

    for filename in uploads:
        # Sign the dist if requested
        if sign:
            sign_file(sign_with, filename, identity)

        # Extract the metadata from the package
        for ext, dtype in DIST_EXTENSIONS.items():
            if filename.endswith(ext):
                meta = DIST_TYPES[dtype](filename)
                break
        else:
            raise ValueError("Unknown distribution format: '%s'" %
                             os.path.basename(filename))

        if dtype == "bdist_egg":
            pkgd = pkg_resources.Distribution.from_filename(filename)
            py_version = pkgd.py_version
        elif dtype == "bdist_wheel":
            py_version = meta.py_version
        elif dtype == "bdist_wininst":
            py_version = meta.py_version
        else:
            py_version = None

        # Fill in the data - send all the meta-data in case we need to
        # register a new release
        data = {
            # action
            ":action": "file_upload",
            "protcol_version": "1",

            # identify release
            "name": pkg_resources.safe_name(meta.name),
            "version": meta.version,

            # file content
            "filetype": dtype,
            "pyversion": py_version,

            # additional meta-data
            "metadata_version": meta.metadata_version,
            "summary": meta.summary,
            "home_page": meta.home_page,
            "author": meta.author,
            "author_email": meta.author_email,
            "maintainer": meta.maintainer,
            "maintainer_email": meta.maintainer_email,
            "license": meta.license,
            "description": meta.description,
            "keywords": meta.keywords,
            "platform": meta.platforms,
            "classifiers": meta.classifiers,
            "download_url": meta.download_url,
            "supported_platform": meta.supported_platforms,
            "comment": comment,

            # PEP 314
            "provides": meta.provides,
            "requires": meta.requires,
            "obsoletes": meta.obsoletes,

            # Metadata 1.2
            "project_urls": meta.project_urls,
            "provides_dist": meta.provides_dist,
            "obsoletes_dist": meta.obsoletes_dist,
            "requires_dist": meta.requires_dist,
            "requires_external": meta.requires_external,
            "requires_python": meta.requires_python,
        }

        with open(filename, "rb") as fp:
            content = fp.read()
            filedata = {
                "content": (os.path.basename(filename), content),
            }
            data["md5_digest"] = hashlib.md5(content).hexdigest()

        signed_name = os.path.basename(filename) + ".asc"
        if signed_name in signatures:
            with open(signatures[signed_name], "rb") as gpg:
                filedata["gpg_signature"] = (signed_name, gpg.read())
        elif sign:
            with open(filename + ".asc", "rb") as gpg:
                filedata["gpg_signature"] = (signed_name, gpg.read())

        print("Uploading {0}".format(os.path.basename(filename)))

        resp = session.post(
            config["repository"],
            data=dict((k, v) for k, v in data.items() if v),
            files=filedata,
            auth=(username, password),
        )
        # Bug 28. Try to silence a ResourceWarning by releasing the socket and
        # clearing the connection pool.
        resp.close()
        session.close()
        resp.raise_for_status()
Ejemplo n.º 19
0
def test_get_password_runtime_error_suppressed(
        entered_password, keyring_no_backends, recwarn):
    assert utils.get_password('system', 'user', None, {}) == 'entered pw'
    assert len(recwarn) == 1
    warning = recwarn.pop(UserWarning)
    assert 'fail!' in str(warning)
Ejemplo n.º 20
0
def upload(dists, repository, sign, identity, username, password, comment,
           sign_with, config_file):
    # Check that a nonsensical option wasn't given
    if not sign and identity:
        raise ValueError("sign must be given along with identity")

    # Determine if the user has passed in pre-signed distributions
    signatures = dict(
        (os.path.basename(d), d) for d in dists if d.endswith(".asc")
    )
    dists = [i for i in dists if not i.endswith(".asc")]

    # Get our config from the .pypirc file
    try:
        config = get_config(config_file)[repository]
    except KeyError:
        msg = (
            "Missing '{repo}' section from the configuration file.\n"
            "Maybe you have a out-dated '{cfg}' format?\n"
            "more info: "
            "https://docs.python.org/distutils/packageindex.html#pypirc\n"
        ).format(
            repo=repository,
            cfg=config_file
        )
        raise KeyError(msg)

    parsed = urlparse(config["repository"])
    if parsed.netloc in ["pypi.python.org", "testpypi.python.org"]:
        config["repository"] = urlunparse(
            ("https",) + parsed[1:]
        )

    print("Uploading distributions to {0}".format(config["repository"]))

    username = get_username(username, config)
    password = get_password(password, config)

    session = requests.session()

    uploads = find_dists(dists)

    for filename in uploads:
        # Sign the dist if requested
        if sign:
            sign_file(sign_with, filename, identity)

        # Extract the metadata from the package
        for ext, dtype in DIST_EXTENSIONS.items():
            if filename.endswith(ext):
                meta = DIST_TYPES[dtype](filename)
                break
        else:
            raise ValueError(
                "Unknown distribution format: '%s'" %
                os.path.basename(filename)
            )

        if dtype == "bdist_egg":
            pkgd = pkg_resources.Distribution.from_filename(filename)
            py_version = pkgd.py_version
        elif dtype == "bdist_wheel":
            py_version = meta.py_version
        elif dtype == "bdist_wininst":
            py_version = meta.py_version
        else:
            py_version = None

        # Fill in the data - send all the meta-data in case we need to
        # register a new release
        data = {
            # action
            ":action": "file_upload",
            "protcol_version": "1",

            # identify release
            "name": pkg_resources.safe_name(meta.name),
            "version": meta.version,

            # file content
            "filetype": dtype,
            "pyversion": py_version,

            # additional meta-data
            "metadata_version": meta.metadata_version,
            "summary": meta.summary,
            "home_page": meta.home_page,
            "author": meta.author,
            "author_email": meta.author_email,
            "maintainer": meta.maintainer,
            "maintainer_email": meta.maintainer_email,
            "license": meta.license,
            "description": meta.description,
            "keywords": meta.keywords,
            "platform": meta.platforms,
            "classifiers": meta.classifiers,
            "download_url": meta.download_url,
            "supported_platform": meta.supported_platforms,
            "comment": comment,

            # PEP 314
            "provides": meta.provides,
            "requires": meta.requires,
            "obsoletes": meta.obsoletes,

            # Metadata 1.2
            "project_urls": meta.project_urls,
            "provides_dist": meta.provides_dist,
            "obsoletes_dist": meta.obsoletes_dist,
            "requires_dist": meta.requires_dist,
            "requires_external": meta.requires_external,
            "requires_python": meta.requires_python,

        }

        md5_hash = hashlib.md5()
        with open(filename, "rb") as fp:
            content = fp.read(4096)
            while content:
                md5_hash.update(content)
                content = fp.read(4096)

        data["md5_digest"] = md5_hash.hexdigest()

        signed_name = os.path.basename(filename) + ".asc"
        if signed_name in signatures:
            with open(signatures[signed_name], "rb") as gpg:
                data["gpg_signature"] = (signed_name, gpg.read())
        elif sign:
            with open(filename + ".asc", "rb") as gpg:
                data["gpg_signature"] = (signed_name, gpg.read())

        print("Uploading {0}".format(os.path.basename(filename)))

        data_to_send = []
        for key, value in data.items():
            if isinstance(value, (list, tuple)):
                for item in value:
                    data_to_send.append((key, item))
            else:
                data_to_send.append((key, value))

        with open(filename, "rb") as fp:
            data_to_send.append((
                "content",
                (os.path.basename(filename), fp, "application/octet-stream"),
            ))
            encoder = MultipartEncoder(data_to_send)
            resp = session.post(
                config["repository"],
                data=encoder,
                auth=(username, password),
                allow_redirects=False,
                headers={'Content-Type': encoder.content_type},
            )
        # Bug 28. Try to silence a ResourceWarning by releasing the socket and
        # clearing the connection pool.
        resp.close()
        session.close()

        # Bug 92. If we get a redirect we should abort because something seems
        # funky. The behaviour is not well defined and redirects being issued
        # by PyPI should never happen in reality. This should catch malicious
        # redirects as well.
        if resp.is_redirect:
            raise exc.RedirectDetected(
                ('"{0}" attempted to redirect to "{1}" during upload.'
                 ' Aborting...').format(config["respository"],
                                        resp.headers["location"]))
        # Otherwise, raise an HTTPError based on the status code.
        resp.raise_for_status()
Ejemplo n.º 21
0
def test_get_password_keyring_missing_prompts(
        entered_password, keyring_missing):
    assert utils.get_password('system', 'user', None, {}) == 'entered pw'
Ejemplo n.º 22
0
def test_empty_password_bypasses_prompt(monkeypatch):
    monkeypatch.setattr(utils, 'password_prompt', lambda prompt: 'entered pw')
    pw = utils.get_password('system', 'user', None, {'password': ''})
    assert pw == ''
Ejemplo n.º 23
0
def test_get_password_keyring_missing_prompts(monkeypatch, keyring_missing):
    monkeypatch.setattr(utils, 'password_prompt', lambda prompt: 'entered pw')

    pw = utils.get_password('system', 'user', None, {})
    assert pw == 'entered pw'
Ejemplo n.º 24
0
def test_no_password_non_interactive_aborts():
    with pytest.raises(exceptions.NonInteractive):
        utils.get_password('system', 'user', None, {'password': None}, True)
Ejemplo n.º 25
0
def test_get_password_runtime_error_suppressed(
        entered_password, keyring_no_backends, recwarn):
    assert utils.get_password('system', 'user', None, {}) == 'entered pw'
    assert len(recwarn) == 1
    warning = recwarn.pop(UserWarning)
    assert 'fail!' in str(warning)
Ejemplo n.º 26
0
def upload(dists, repository, sign, identity, username, password, comment,
           sign_with, config_file):
    # Check that a nonsensical option wasn't given
    if not sign and identity:
        raise ValueError("sign must be given along with identity")

    # Determine if the user has passed in pre-signed distributions
    signatures = dict(
        (os.path.basename(d), d) for d in dists if d.endswith(".asc")
    )
    dists = [i for i in dists if not i.endswith(".asc")]

    # Get our config from the .pypirc file
    try:
        config = get_config(config_file)[repository]
    except KeyError:
        raise KeyError(
            "Missing '{0}' section from the configuration file".format(
                repository,
            ),
        )

    parsed = urlparse(config["repository"])
    if parsed.netloc in ["pypi.python.org", "testpypi.python.org"]:
        config["repository"] = urlunparse(
            ("https",) + parsed[1:]
        )

    print("Uploading distributions to {0}".format(config["repository"]))

    username = get_username(username, config)
    password = get_password(password, config)

    session = requests.session()

    uploads = find_dists(dists)

    for filename in uploads:
        # Sign the dist if requested
        if sign:
            sign_file(sign_with, filename, identity)

        # Extract the metadata from the package
        for ext, dtype in DIST_EXTENSIONS.items():
            if filename.endswith(ext):
                meta = DIST_TYPES[dtype](filename)
                break
        else:
            raise ValueError(
                "Unknown distribution format: '%s'" %
                os.path.basename(filename)
            )

        if dtype == "bdist_egg":
            pkgd = pkg_resources.Distribution.from_filename(filename)
            py_version = pkgd.py_version
        elif dtype == "bdist_wheel":
            py_version = meta.py_version
        elif dtype == "bdist_wininst":
            py_version = meta.py_version
        else:
            py_version = None

        # Fill in the data - send all the meta-data in case we need to
        # register a new release
        data = {
            # action
            ":action": "file_upload",
            "protcol_version": "1",

            # identify release
            "name": pkg_resources.safe_name(meta.name),
            "version": meta.version,

            # file content
            "filetype": dtype,
            "pyversion": py_version,

            # additional meta-data
            "metadata_version": meta.metadata_version,
            "summary": meta.summary,
            "home_page": meta.home_page,
            "author": meta.author,
            "author_email": meta.author_email,
            "maintainer": meta.maintainer,
            "maintainer_email": meta.maintainer_email,
            "license": meta.license,
            "description": meta.description,
            "keywords": meta.keywords,
            "platform": meta.platforms,
            "classifiers": meta.classifiers,
            "download_url": meta.download_url,
            "supported_platform": meta.supported_platforms,
            "comment": comment,

            # PEP 314
            "provides": meta.provides,
            "requires": meta.requires,
            "obsoletes": meta.obsoletes,

            # Metadata 1.2
            "project_urls": meta.project_urls,
            "provides_dist": meta.provides_dist,
            "obsoletes_dist": meta.obsoletes_dist,
            "requires_dist": meta.requires_dist,
            "requires_external": meta.requires_external,
            "requires_python": meta.requires_python,

        }

        with open(filename, "rb") as fp:
            content = fp.read()
            filedata = {
                "content": (os.path.basename(filename), content),
            }
            data["md5_digest"] = hashlib.md5(content).hexdigest()

        signed_name = os.path.basename(filename) + ".asc"
        if signed_name in signatures:
            with open(signatures[signed_name], "rb") as gpg:
                filedata["gpg_signature"] = (signed_name, gpg.read())
        elif sign:
            with open(filename + ".asc", "rb") as gpg:
                filedata["gpg_signature"] = (signed_name, gpg.read())

        print("Uploading {0}".format(os.path.basename(filename)))

        resp = session.post(
            config["repository"],
            data=dict((k, v) for k, v in data.items() if v),
            files=filedata,
            auth=(username, password),
        )
        # Bug 28. Try to silence a ResourceWarning by releasing the socket and
        # clearing the connection pool.
        resp.close()
        session.close()
        resp.raise_for_status()
Ejemplo n.º 27
0
def test_get_password_keyring_missing_prompts(
        entered_password, keyring_missing):
    assert utils.get_password('system', 'user', None, {}) == 'entered pw'
Ejemplo n.º 28
0
def test_get_password_keyring_missing_prompts(monkeypatch, keyring_missing):
    monkeypatch.setattr(utils, 'password_prompt', lambda prompt: 'entered pw')

    pw = utils.get_password('system', 'user', None, {})
    assert pw == 'entered pw'
Ejemplo n.º 29
0
def upload(dists, repository, sign, identity, username, password, comment,
           sign_with, config_file):
    # Check that a nonsensical option wasn't given
    if not sign and identity:
        raise ValueError("sign must be given along with identity")

    # Determine if the user has passed in pre-signed distributions
    signatures = dict(
        (os.path.basename(d), d) for d in dists if d.endswith(".asc"))
    dists = [i for i in dists if not i.endswith(".asc")]

    # Get our config from the .pypirc file
    try:
        config = get_config(config_file)[repository]
    except KeyError:
        raise KeyError(
            "Missing '{0}' section from the configuration file".format(
                repository, ), )

    parsed = urlparse(config["repository"])
    if parsed.netloc in ["pypi.python.org", "testpypi.python.org"]:
        config["repository"] = urlunparse(("https", ) + parsed[1:])

    print("Uploading distributions to {0}".format(config["repository"]))

    username = get_username(username, config)
    password = get_password(password, config)

    session = requests.session()

    uploads = find_dists(dists)

    for filename in uploads:
        # Sign the dist if requested
        if sign:
            sign_file(sign_with, filename, identity)

        # Extract the metadata from the package
        for ext, dtype in DIST_EXTENSIONS.items():
            if filename.endswith(ext):
                meta = DIST_TYPES[dtype](filename)
                break
        else:
            raise ValueError("Unknown distribution format: '%s'" %
                             os.path.basename(filename))

        if dtype == "bdist_egg":
            pkgd = pkg_resources.Distribution.from_filename(filename)
            py_version = pkgd.py_version
        elif dtype == "bdist_wheel":
            py_version = meta.py_version
        elif dtype == "bdist_wininst":
            py_version = meta.py_version
        else:
            py_version = None

        # Fill in the data - send all the meta-data in case we need to
        # register a new release
        data = {
            # action
            ":action": "file_upload",
            "protcol_version": "1",

            # identify release
            "name": pkg_resources.safe_name(meta.name),
            "version": meta.version,

            # file content
            "filetype": dtype,
            "pyversion": py_version,

            # additional meta-data
            "metadata_version": meta.metadata_version,
            "summary": meta.summary,
            "home_page": meta.home_page,
            "author": meta.author,
            "author_email": meta.author_email,
            "maintainer": meta.maintainer,
            "maintainer_email": meta.maintainer_email,
            "license": meta.license,
            "description": meta.description,
            "keywords": meta.keywords,
            "platform": meta.platforms,
            "classifiers": meta.classifiers,
            "download_url": meta.download_url,
            "supported_platform": meta.supported_platforms,
            "comment": comment,

            # PEP 314
            "provides": meta.provides,
            "requires": meta.requires,
            "obsoletes": meta.obsoletes,

            # Metadata 1.2
            "project_urls": meta.project_urls,
            "provides_dist": meta.provides_dist,
            "obsoletes_dist": meta.obsoletes_dist,
            "requires_dist": meta.requires_dist,
            "requires_external": meta.requires_external,
            "requires_python": meta.requires_python,
        }

        md5_hash = hashlib.md5()
        with open(filename, "rb") as fp:
            content = fp.read(4096)
            while content:
                md5_hash.update(content)
                content = fp.read(4096)

        data["md5_digest"] = md5_hash.hexdigest()

        signed_name = os.path.basename(filename) + ".asc"
        if signed_name in signatures:
            with open(signatures[signed_name], "rb") as gpg:
                data["gpg_signature"] = (signed_name, gpg.read())
        elif sign:
            with open(filename + ".asc", "rb") as gpg:
                data["gpg_signature"] = (signed_name, gpg.read())

        print("Uploading {0}".format(os.path.basename(filename)))

        data_to_send = []
        for key, value in data.items():
            if isinstance(value, (list, tuple)):
                for item in value:
                    data_to_send.append((key, item))
            else:
                data_to_send.append((key, value))

        with open(filename, "rb") as fp:
            data_to_send.append((
                "content",
                (os.path.basename(filename), fp, "application/octet-stream"),
            ))
            encoder = MultipartEncoder(data_to_send)
            resp = session.post(
                config["repository"],
                data=encoder,
                auth=(username, password),
                allow_redirects=False,
                headers={'Content-Type': encoder.content_type},
            )
        # Bug 28. Try to silence a ResourceWarning by releasing the socket and
        # clearing the connection pool.
        resp.close()
        session.close()

        # Bug 92. If we get a redirect we should abort because something seems
        # funky. The behaviour is not well defined and redirects being issued
        # by PyPI should never happen in reality. This should catch malicious
        # redirects as well.
        if resp.is_redirect:
            raise exc.RedirectDetected(
                ('"{0}" attempted to redirect to "{1}" during upload.'
                 ' Aborting...').format(config["respository"],
                                        resp.headers["location"]))
        # Otherwise, raise an HTTPError based on the status code.
        resp.raise_for_status()