def post(self): """ Convert the user to an organization. """ user = get_authenticated_user() convert_data = request.get_json() # Ensure that the sign in credentials work. admin_username = convert_data["adminUser"] admin_password = convert_data["adminPassword"] (admin_user, _) = authentication.verify_and_link_user(admin_username, admin_password) if not admin_user: raise request_error( reason="invaliduser", message="The admin user credentials are not valid" ) # Ensure that the new admin user is the not user being converted. if admin_user.id == user.id: raise request_error(reason="invaliduser", message="The admin user is not valid") # Subscribe the organization to the new plan. if features.BILLING: plan = convert_data.get("plan", "free") subscribe(user, plan, None, True) # Require business plans # Convert the user to an organization. model.organization.convert_user_to_organization(user, admin_user) log_action("account_convert", user.username) # And finally login with the admin credentials. return conduct_signin(admin_username, admin_password)
def post(self, orgname): """ Create a new organization quota. """ if not SuperUserPermission().can(): raise Unauthorized() quota_data = request.get_json() limit_bytes = quota_data["limit_bytes"] try: org = model.organization.get_organization(orgname) except model.InvalidOrganizationException: raise NotFound() # Currently only supporting one quota definition per namespace quotas = model.namespacequota.get_namespace_quota_list(orgname) if quotas: raise request_error( message="Organization quota for '%s' already exists" % orgname) try: model.namespacequota.create_namespace_quota(org, limit_bytes) return "Created", 201 except model.DataModelException as ex: raise request_error(exception=ex)
def post(self, orgname, quota_id): if not SuperUserPermission().can(): raise Unauthorized() quota_limit_data = request.get_json() quota_type = quota_limit_data["type"] quota_limit_threshold = quota_limit_data["threshold_percent"] quota = get_quota(orgname, quota_id) quota_limit = model.namespacequota.get_namespace_quota_limit_list( quota, quota_type=quota_type, percent_of_limit=quota_limit_threshold, ) if quota_limit: msg = "Quota limit already exists" raise request_error(message=msg) if quota_limit_data["type"].lower() == "reject" and quota_limit: raise request_error( message="Only one quota limit of type 'Reject' allowed.") try: model.namespacequota.create_namespace_quota_limit( quota, quota_type, quota_limit_threshold, ) return "Created", 201 except model.DataModelException as ex: raise request_error(exception=ex)
def post(self, orgname): """ Creates proxy cache configuration for the organization. """ permission = AdministerOrganizationPermission(orgname) if not permission.can(): raise Unauthorized() try: model.proxy_cache.get_proxy_cache_config_for_org(orgname) raise request_error("Proxy Cache Configuration already exists") except model.InvalidProxyCacheConfigException: pass data = request.get_json() # filter None values data = {k: v for k, v in data.items() if (v is not None or not "")} try: config = model.proxy_cache.create_proxy_cache_config(**data) if config is not None: return "Created", 201 except model.DataModelException as e: logger.error( "Error while creating Proxy cache configuration as: %s", str(e)) return request_error("Error while creating Proxy cache configuration")
def post(self, orgname): permission = AdministerOrganizationPermission(orgname) if not permission.can(): raise Unauthorized() try: model.proxy_cache.get_proxy_cache_config_for_org(orgname) request_error("Proxy Cache Configuration already exists") except model.InvalidProxyCacheConfigException: pass data = request.get_json() # filter None values data = {k: v for k, v in data.items() if v is not None} try: config = ProxyCacheConfig(**data) existing = model.organization.get_organization(orgname) config.organization = existing proxy = Proxy(config, "something-totally-fake", True) response = proxy.get(f"{proxy.base_url}/v2/") if response.status_code == 200: return "Valid", 202 except UpstreamRegistryError as e: raise request_error( message= "Failed login to remote registry. Please verify entered details and try again." ) raise request_error( message="Failed to validate Proxy cache configuration")
def post(self, orgname): """ Create a new permission prototype. """ permission = AdministerOrganizationPermission(orgname) if permission.can(): try: org = model.organization.get_organization(orgname) except model.InvalidOrganizationException: raise NotFound() details = request.get_json() activating_username = None if ( "activating_user" in details and details["activating_user"] and "name" in details["activating_user"] ): activating_username = details["activating_user"]["name"] delegate = details["delegate"] if "delegate" in details else {} delegate_kind = delegate.get("kind", None) delegate_name = delegate.get("name", None) delegate_username = delegate_name if delegate_kind == "user" else None delegate_teamname = delegate_name if delegate_kind == "team" else None activating_user = ( model.user.get_user(activating_username) if activating_username else None ) delegate_user = model.user.get_user(delegate_username) if delegate_username else None delegate_team = ( model.team.get_organization_team(orgname, delegate_teamname) if delegate_teamname else None ) if activating_username and not activating_user: raise request_error(message="Unknown activating user") if not delegate_user and not delegate_team: raise request_error(message="Missing delegate user or team") role_name = details["role"] prototype = model.permission.add_prototype_permission( org, role_name, activating_user, delegate_user, delegate_team ) log_prototype_action("create_prototype_permission", orgname, prototype) users_filter = {prototype.activating_user, prototype.delegate_user} org_members = model.organization.get_organization_member_set( org, users_filter=users_filter ) return prototype_view(prototype, org_members) raise Unauthorized()
def post(self, orgname): """ Create a new permission prototype. """ permission = AdministerOrganizationPermission(orgname) if permission.can(): try: org = model.organization.get_organization(orgname) except model.InvalidOrganizationException: raise NotFound() details = request.get_json() activating_username = None if ('activating_user' in details and details['activating_user'] and 'name' in details['activating_user']): activating_username = details['activating_user']['name'] delegate = details['delegate'] if 'delegate' in details else {} delegate_kind = delegate.get('kind', None) delegate_name = delegate.get('name', None) delegate_username = delegate_name if delegate_kind == 'user' else None delegate_teamname = delegate_name if delegate_kind == 'team' else None activating_user = (model.user.get_user(activating_username) if activating_username else None) delegate_user = (model.user.get_user(delegate_username) if delegate_username else None) delegate_team = (model.team.get_organization_team( orgname, delegate_teamname) if delegate_teamname else None) if activating_username and not activating_user: raise request_error(message='Unknown activating user') if not delegate_user and not delegate_team: raise request_error(message='Missing delegate user or team') role_name = details['role'] prototype = model.permission.add_prototype_permission( org, role_name, activating_user, delegate_user, delegate_team) log_prototype_action('create_prototype_permission', orgname, prototype) users_filter = {prototype.activating_user, prototype.delegate_user} org_members = model.organization.get_organization_member_set( org, users_filter=users_filter) return prototype_view(prototype, org_members) raise Unauthorized()
def post(self): """ Create a new organization. """ user = get_authenticated_user() org_data = request.get_json() existing = None try: existing = model.organization.get_organization(org_data["name"]) except model.InvalidOrganizationException: pass if not existing: existing = model.user.get_user(org_data["name"]) if existing: msg = "A user or organization with this name already exists" raise request_error(message=msg) if features.MAILING and not org_data.get("email"): raise request_error(message="Email address is required") # If recaptcha is enabled, then verify the user is a human. if features.RECAPTCHA: recaptcha_response = org_data.get("recaptcha_response", "") result = recaptcha2.verify(app.config["RECAPTCHA_SECRET_KEY"], recaptcha_response, get_request_ip()) if not result["success"]: return { "message": "Are you a bot? If not, please revalidate the captcha." }, 400 is_possible_abuser = ip_resolver.is_ip_possible_threat( get_request_ip()) try: model.organization.create_organization( org_data["name"], org_data.get("email"), user, email_required=features.MAILING, is_possible_abuser=is_possible_abuser, ) return "Created", 201 except model.DataModelException as ex: raise request_error(exception=ex)
def put(self, namespace_name, repository_name, teamname): """ Update the existing team permission. """ new_permission = request.get_json() logger.debug("Setting permission to: %s for team %s", new_permission["role"], teamname) try: perm = model.set_repo_permission_for_team(teamname, namespace_name, repository_name, new_permission["role"]) resp = perm.to_dict() except SaveException as ex: raise request_error(exception=ex) log_action( "change_repo_permission", namespace_name, { "team": teamname, "repo": repository_name, "role": new_permission["role"] }, repo_name=repository_name, ) return resp, 200
def put(self, namespace_name, repository_name, username): # Also needs to respond to post """ Update the perimssions for an existing repository. """ new_permission = request.get_json() logger.debug("Setting permission to: %s for user %s", new_permission["role"], username) try: perm = model.set_repo_permission_for_user(username, namespace_name, repository_name, new_permission["role"]) resp = perm.to_dict() except SaveException as ex: raise request_error(exception=ex) log_action( "change_repo_permission", namespace_name, { "username": username, "repo": repository_name, "namespace": namespace_name, "role": new_permission["role"], }, repo_name=repository_name, ) return resp, 200
def post(self, namespace_name, repository_name): parsed = request.get_json() method_handler = NotificationMethod.get_method(parsed["method"]) try: method_handler.validate(namespace_name, repository_name, parsed["config"]) except CannotValidateNotificationMethodException as ex: raise request_error(message=ex.message) new_notification = model.create_repo_notification( namespace_name, repository_name, parsed["event"], parsed["method"], parsed["config"], parsed["eventConfig"], parsed.get("title"), ) log_action( "add_repo_notification", namespace_name, { "repo": repository_name, "namespace": namespace_name, "notification_id": new_notification.uuid, "event": new_notification.event_name, "method": new_notification.method_name, }, repo_name=repository_name, ) return new_notification.to_dict(), 201
def post(self): """ Create a new repository. """ owner = get_authenticated_user() req = request.get_json() if owner is None and "namespace" not in "req": raise InvalidRequest( "Must provide a namespace or must be logged in.") namespace_name = req[ "namespace"] if "namespace" in req else owner.username permission = CreateRepositoryPermission(namespace_name) if permission.can(): repository_name = req["repository"] visibility = req["visibility"] if model.repo_exists(namespace_name, repository_name): raise request_error(message="Repository already exists") visibility = req["visibility"] if visibility == "private": check_allowed_private_repos(namespace_name) # Verify that the repository name is valid. if not REPOSITORY_NAME_REGEX.match(repository_name): raise InvalidRequest("Invalid repository name") kind = req.get("repo_kind", "image") or "image" created = model.create_repo( namespace_name, repository_name, owner, req["description"], visibility=visibility, repo_kind=kind, ) if created is None: raise InvalidRequest("Could not create repository") log_action( "create_repo", namespace_name, { "repo": repository_name, "namespace": namespace_name }, repo_name=repository_name, ) return { "namespace": namespace_name, "name": repository_name, "kind": kind, }, 201 raise Unauthorized()
def post(self): """ Create a new organization. """ user = get_authenticated_user() org_data = request.get_json() existing = None try: existing = model.organization.get_organization(org_data['name']) except model.InvalidOrganizationException: pass if not existing: existing = model.user.get_user(org_data['name']) if existing: msg = 'A user or organization with this name already exists' raise request_error(message=msg) if features.MAILING and not org_data.get('email'): raise request_error(message='Email address is required') # If recaptcha is enabled, then verify the user is a human. if features.RECAPTCHA: recaptcha_response = org_data.get('recaptcha_response', '') result = recaptcha2.verify(app.config['RECAPTCHA_SECRET_KEY'], recaptcha_response, get_request_ip()) if not result['success']: return { 'message': 'Are you a bot? If not, please revalidate the captcha.' }, 400 is_possible_abuser = ip_resolver.is_ip_possible_threat( get_request_ip()) try: model.organization.create_organization( org_data['name'], org_data.get('email'), user, email_required=features.MAILING, is_possible_abuser=is_possible_abuser) return 'Created', 201 except model.DataModelException as ex: raise request_error(exception=ex)
def post(self, namespace): if SuperUserPermission().can(): quota_data = request.get_json() limit_bytes = quota_data["limit_bytes"] namespace_user = user.get_user_or_org(namespace) quotas = namespacequota.get_namespace_quota_list( namespace_user.username) if quotas: raise request_error(message="Quota for '%s' already exists" % namespace) try: newquota = namespacequota.create_namespace_quota( namespace_user, limit_bytes) return "Created", 201 except DataModelException as ex: raise request_error(exception=ex) raise Unauthorized()
def delete(self, namespace_name, repository_name, teamname): """ Delete the permission for the specified team. """ try: model.delete_repo_permission_for_team(teamname, namespace_name, repository_name) except DeleteException as ex: raise request_error(exception=ex) log_action('delete_repo_permission', namespace_name, {'team': teamname, 'repo': repository_name}, repo_name=repository_name) return '', 204
def delete(self, namespace_name, repository_name, username): """ Delete the permission for the user. """ try: model.delete_repo_permission_for_user(username, namespace_name, repository_name) except DeleteException as ex: raise request_error(exception=ex) log_action('delete_repo_permission', namespace_name, {'username': username, 'repo': repository_name, 'namespace': namespace_name}, repo_name=repository_name) return '', 204
def post(self): """ Return's the user's private client key. """ if not authentication.supports_encrypted_credentials: raise NotFound() username = get_authenticated_user().username password = request.get_json()["password"] (result, error_message) = authentication.confirm_existing_user(username, password) if not result: raise request_error(message=error_message) return {"key": authentication.encrypt_user_password(password)}
def post(self): """Create a new repository.""" owner = get_authenticated_user() req = request.get_json() if owner is None and 'namespace' not in 'req': raise InvalidRequest( 'Must provide a namespace or must be logged in.') namespace_name = req[ 'namespace'] if 'namespace' in req else owner.username permission = CreateRepositoryPermission(namespace_name) if permission.can(): repository_name = req['repository'] visibility = req['visibility'] if model.repo_exists(namespace_name, repository_name): raise request_error(message='Repository already exists') visibility = req['visibility'] if visibility == 'private': check_allowed_private_repos(namespace_name) # Verify that the repository name is valid. if not REPOSITORY_NAME_REGEX.match(repository_name): raise InvalidRequest('Invalid repository name') kind = req.get('repo_kind', 'image') or 'image' model.create_repo(namespace_name, repository_name, owner, req['description'], visibility=visibility, repo_kind=kind) log_action('create_repo', namespace_name, { 'repo': repository_name, 'namespace': namespace_name }, repo_name=repository_name) return { 'namespace': namespace_name, 'name': repository_name, 'kind': kind, }, 201 raise Unauthorized()
def delete(self, orgname, robot_shortname): """ Delete an existing organization robot. """ permission = AdministerOrganizationPermission(orgname) if permission.can(): robot_username = format_robot_username(orgname, robot_shortname) if not model.robot_has_mirror(robot_username): model.delete_robot(robot_username) log_action("delete_robot", orgname, {"robot": robot_shortname}) return "", 204 else: raise request_error(message="Robot is being used by a mirror") raise Unauthorized()
def delete(self, robot_shortname): """ Delete an existing robot. """ parent = get_authenticated_user() robot_username = format_robot_username(parent.username, robot_shortname) if not model.robot_has_mirror(robot_username): model.delete_robot(robot_username) log_action("delete_robot", parent.username, {"robot": robot_shortname}) return "", 204 else: raise request_error(message="Robot is being used by a mirror")
def put(self, orgname, quota_id): if not SuperUserPermission().can(): raise Unauthorized() quota_data = request.get_json() quota = get_quota(orgname, quota_id) try: if "limit_bytes" in quota_data: limit_bytes = quota_data["limit_bytes"] model.namespacequota.update_namespace_quota_size( quota, limit_bytes) except model.DataModelException as ex: raise request_error(exception=ex) return quota_view(quota)
def delete(self, orgname, quota_id, limit_id): if not SuperUserPermission().can(): raise Unauthorized() quota = get_quota(orgname, quota_id) quota_limit = model.namespacequota.get_namespace_quota_limit( quota, limit_id) if quota_limit is None: raise NotFound() try: # Exceptions by`delete_instance` are unexpected and raised model.namespacequota.delete_namespace_quota_limit(quota_limit) return "", 204 except model.DataModelException as ex: raise request_error(exception=ex)
def put(self, orgname): """ Change the details for the specified organization. """ permission = AdministerOrganizationPermission(orgname) if permission.can(): try: org = model.organization.get_organization(orgname) except model.InvalidOrganizationException: raise NotFound() org_data = request.get_json() if "invoice_email" in org_data: logger.debug("Changing invoice_email for organization: %s", org.username) model.user.change_send_invoice_email(org, org_data["invoice_email"]) if ("invoice_email_address" in org_data and org_data["invoice_email_address"] != org.invoice_email_address): new_email = org_data["invoice_email_address"] logger.debug( "Changing invoice email address for organization: %s", org.username) model.user.change_invoice_email_address(org, new_email) if "email" in org_data and org_data["email"] != org.email: new_email = org_data["email"] if model.user.find_user_by_email(new_email): raise request_error(message="E-mail address already used") logger.debug("Changing email address for organization: %s", org.username) model.user.update_email(org, new_email) if features.CHANGE_TAG_EXPIRATION and "tag_expiration_s" in org_data: logger.debug("Changing organization tag expiration to: %ss", org_data["tag_expiration_s"]) model.user.change_user_tag_expiration( org, org_data["tag_expiration_s"]) teams = model.team.get_teams_within_org(org) return org_view(org, teams) raise Unauthorized()
def put(self, namespace, quota_id): if SuperUserPermission().can(): quota_data = request.get_json() namespace_user = user.get_user_or_org(namespace) quota = get_quota(namespace_user.username, quota_id) try: if "limit_bytes" in quota_data: limit_bytes = quota_data["limit_bytes"] namespacequota.update_namespace_quota_size( quota, limit_bytes) except DataModelException as ex: raise request_error(exception=ex) return quota_view(quota) raise Unauthorized()
def put(self, orgname, teamname, membername): """ Adds or invites a member to an existing team. """ permission = AdministerOrganizationPermission(orgname) if permission.can(): team = None user = None # Find the team. try: team = model.team.get_organization_team(orgname, teamname) except model.InvalidTeamException: raise NotFound() # Find the user. user = model.user.get_user(membername) if not user: raise request_error(message="Unknown user") # Add or invite the user to the team. inviter = get_authenticated_user() invite = handle_addinvite_team(inviter, team, user=user) if not invite: log_action("org_add_team_member", orgname, { "member": membername, "team": teamname }) return member_view(user, invited=False) # User was invited. log_action( "org_invite_team_member", orgname, { "user": membername, "member": membername, "team": teamname }, ) return member_view(user, invited=True) raise Unauthorized()
def put(self, namespace_name, repository_name, teamname): """ Update the existing team permission. """ new_permission = request.get_json() logger.debug('Setting permission to: %s for team %s', new_permission['role'], teamname) try: perm = model.set_repo_permission_for_team(teamname, namespace_name, repository_name, new_permission['role']) resp = perm.to_dict() except SaveException as ex: raise request_error(exception=ex) log_action('change_repo_permission', namespace_name, {'team': teamname, 'repo': repository_name, 'role': new_permission['role']}, repo_name=repository_name) return resp, 200
def delete(self, namespace_name, repository_name, teamname): """ Delete the permission for the specified team. """ try: model.delete_repo_permission_for_team(teamname, namespace_name, repository_name) except DeleteException as ex: raise request_error(exception=ex) log_action( "delete_repo_permission", namespace_name, { "team": teamname, "repo": repository_name }, repo_name=repository_name, ) return "", 204
def put(self, namespace_name, repository_name, username): # Also needs to respond to post """ Update the perimssions for an existing repository. """ new_permission = request.get_json() logger.debug('Setting permission to: %s for user %s', new_permission['role'], username) try: perm = model.set_repo_permission_for_user(username, namespace_name, repository_name, new_permission['role']) resp = perm.to_dict() except SaveException as ex: raise request_error(exception=ex) log_action('change_repo_permission', namespace_name, {'username': username, 'repo': repository_name, 'namespace': namespace_name, 'role': new_permission['role']}, repo_name=repository_name) return resp, 200
def delete(self, namespace_name, repository_name, username): """ Delete the permission for the user. """ try: model.delete_repo_permission_for_user(username, namespace_name, repository_name) except DeleteException as ex: raise request_error(exception=ex) log_action( "delete_repo_permission", namespace_name, { "username": username, "repo": repository_name, "namespace": namespace_name }, repo_name=repository_name, ) return "", 204
def delete(self, orgname): """ Delete proxy cache configuration for the organization. """ permission = AdministerOrganizationPermission(orgname) if not permission.can(): raise Unauthorized() try: model.proxy_cache.get_proxy_cache_config_for_org(orgname) except model.InvalidProxyCacheConfigException: raise NotFound() try: success = model.proxy_cache.delete_proxy_cache_config(orgname) if success: return "Deleted", 201 except model.DataModelException as e: logger.error( "Error while deleting Proxy cache configuration as: %s", str(e)) raise request_error( message="Proxy Cache Configuration failed to delete")