Skip to content
This repository has been archived by the owner on Apr 17, 2023. It is now read-only.

Commit

Permalink
Added permissions and an internal API layer
Browse files Browse the repository at this point in the history
- It introduces the `permissions` object to the namespace entity.
- Some fields will now be returned only to the web application, but not to
  external clients.

Signed-off-by: Miquel Sabaté Solà <msabate@suse.com>
  • Loading branch information
mssola committed Sep 21, 2017
1 parent cb88ebb commit 185f18e
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 32 deletions.
4 changes: 0 additions & 4 deletions app/helpers/namespaces_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ def can_change_visibility?(namespace)
APP_CONFIG.enabled?("user_permission.change_visibility"))
end

def can_view_webhooks?(namespace)
current_user.admin? || namespace.team.users.include?(current_user)
end

def owner?(namespace)
namespace.team.owners.exists?(current_user.id)
end
Expand Down
4 changes: 2 additions & 2 deletions app/models/namespace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ class Namespace < ActiveRecord::Base
attributes :name, :description
end

scope :special_for, -> (user) {
where("global = ? OR namespaces.name = ?", true, user.username)
scope :special_for, lambda { |user|
where("global = ? OR namespaces.id = ?", true, user.namespace_id)
}

# This regexp is extracted from the reference package of Docker Distribution
Expand Down
21 changes: 15 additions & 6 deletions lib/api/entities.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,15 +95,11 @@ class Namespaces < Grape::Entity
expose :repositories_count, documentation: {
type: Integer,
desc: "The number of repositories that belong to this namespace"
} { |n| n.repositories.count }
}, if: { type: :internal } { |n| n.repositories.count }
expose :webhooks_count, documentation: {
type: Integer,
desc: "The number of webooks that belong to this namespace"
} { |n| n.webhooks.count }
expose :registry_id, documentation: {
type: Integer,
desc: "The ID of the registry containing this namespace"
}
}, if: { type: :internal } { |n| n.webhooks.count }
expose :visibility, documentation: {
type: String,
desc: "The visibility of namespaces by other people"
Expand All @@ -114,6 +110,19 @@ class Namespaces < Grape::Entity
type: "Boolean",
desc: "Whether this is the global namespace or not"
}
expose :permissions, documentation: {
desc: "Different permissions for the current user"
}, if: { type: :internal } do |namespace, options|
user = options[:current_user]
# TODO: taken from NamespacesHelper. Avoid duplication! (e.g. owner?)
{
webhooks: user.admin? ||
namespace.team.users.include?(user),
visibility: user.admin? ||
(namespace.team.owners.exists?(user.id) &&
APP_CONFIG.enabled?("user_permission.change_visibility"))
}
end
end
end
end
46 changes: 37 additions & 9 deletions lib/api/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,57 @@ module Helpers
# The `force_admin` option should be used when the endpoints affected by
# this should only apply to Portus administrators (e.g. user management).
def authorization!(force_admin: true)
return if current_user
return if request.request_method == "OPTIONS"
@user = authenticate_user_from_authentication_token!

current_user

error!("Authentication fails.", 401) unless @user
raise Pundit::NotAuthorizedError if force_admin && !@user.admin
end

# Helper method to make Pundit happy. It will return the `@user` instance
# variable set by the `authorization!` method or the current user as stored
# by Devise.
def current_user
return @user if @user

# Authenticate from the warden session if possible.
def authenticate_from_warden
warden = env["warden"]
return unless warden

@user = env["warden"].authenticate(scope: "user")
env["warden"].authenticate(scope: "user")
end

# Helper method to make Pundit happy. It will set a `@user` instance
# variable with either the current user as stored by Devise or the one taken
# from the authentication token.
def current_user
@user = authenticate_from_warden
if @user
@type = :internal
else
@type = :official
@user = authenticate_user_from_authentication_token!
end
@user
end

# TODO: really ?
def user_session
current_user && warden.session(:user)
end

# Returns the current type of API presentation. The two options available
# are: :official and :internal. The :internal type is the same as the
# official one, but with some extensions that come in handy for the client
# side.
def current_type
@type
end

# Helpers for namespaces
module Namespaces
# Returns an aggregate of the accessible namespaces for the current user.
def accessible_namespaces
special = Namespace.special_for(current_user).order(created_at: :asc)
normal = policy_scope(Namespace).order(created_at: :asc)
special + normal
end
end
end
end
22 changes: 12 additions & 10 deletions lib/api/v1/namespaces.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,7 @@ class Namespaces < Grape::API
authorization!(force_admin: false)
end

helpers do
def accessible_namespaces
special = Namespace.special_for(current_user).order(created_at: :asc)
normal = policy_scope(Namespace).order(created_at: :asc)
special + normal
end
end
helpers ::API::Helpers::Namespaces

desc "Returns a list of namespaces.",
tags: ["namespaces"],
Expand All @@ -27,7 +21,10 @@ def accessible_namespaces
]

get do
present accessible_namespaces, with: API::Entities::Namespaces
present accessible_namespaces,
with: API::Entities::Namespaces,
current_user: current_user,
type: current_type
end

route_param :id, type: String, requirements: { id: /.*/ } do
Expand All @@ -45,7 +42,9 @@ def accessible_namespaces
get do
namespace = Namespace.find params[:id]
authorize namespace, :show?
present namespace.repositories, with: API::Entities::Repositories
present namespace.repositories,
with: API::Entities::Repositories,
type: current_type
end
end

Expand All @@ -64,7 +63,10 @@ def accessible_namespaces
get do
namespace = Namespace.find(params[:id])
authorize namespace, :show?
present namespace, with: API::Entities::Namespaces
present namespace,
with: API::Entities::Namespaces,
current_user: current_user,
type: current_type
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/api/v1/teams.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class Teams < Grape::API
get do
team = Team.find params[:id]
authorize team, :show?
present team.namespaces, with: API::Entities::Namespaces
present team.namespaces, with: API::Entities::Namespaces, type: current_type
end
end

Expand Down

0 comments on commit 185f18e

Please sign in to comment.