summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Trzciński <ayufan@ayufan.eu>2019-04-24 13:54:46 +0200
committerKamil Trzciński <ayufan@ayufan.eu>2019-04-24 14:48:52 +0200
commit5fc045114c9b6faf0e7f506f0af06b8ca3a2996b (patch)
tree69e8118885a933ab513ee207ee884cac088b4d35
parent2a00858533f1dcae71e97ba52386bfb2bfc1f752 (diff)
downloadgitlab-ce-pages-host-api.tar.gz
Add `token`pages-host-api
-rw-r--r--app/models/project.rb36
-rw-r--r--app/models/project_feature.rb4
-rw-r--r--config/gitlab.yml.example1
-rw-r--r--lib/api/entities.rb39
-rw-r--r--lib/api/helpers.rb13
-rw-r--r--lib/api/internals/pages.rb67
6 files changed, 93 insertions, 67 deletions
diff --git a/app/models/project.rb b/app/models/project.rb
index 2e72de4e447..36b16a53fe8 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -1566,23 +1566,37 @@ class Project < ApplicationRecord
def pages_group_url
# The host in URL always needs to be downcased
- Gitlab.config.pages.url.sub(%r{^https?://}) do |prefix|
- "#{prefix}#{pages_subdomain}."
- end.downcase
+ strong_memoize(:pages_group_url) do
+ Gitlab.config.pages.url.sub(%r{^https?://}) do |prefix|
+ "#{prefix}#{pages_subdomain}."
+ end.downcase
+ end
end
- def pages_url
- url = pages_group_url
- url_path = full_path.partition('/').last
-
- # If the project path is the same as host, we serve it as group page
- return url if url == "#{Settings.pages.protocol}://#{url_path}"
+ def pages_group_root?
+ strong_memoize(:pages_group_root?) do
+ pages_group_url == "#{Settings.pages.protocol}://#{pages_path}"
+ end
+ end
- "#{url}/#{url_path}"
+ def pages_url
+ if pages_group_root?
+ pages_group_url
+ else
+ "#{pages_group_url}/#{pages_path}"
+ end
end
def pages_subdomain
- full_path.partition('/').first
+ strong_memoize(:pages_subdomain) do
+ full_path.partition('/').first
+ end
+ end
+
+ def pages_path
+ strong_memoize(:pages_path) do
+ full_path.partition('/').drop(1).join('/')
+ end
end
def pages_path
diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb
index 0542581c6e0..b6fb2c459bd 100644
--- a/app/models/project_feature.rb
+++ b/app/models/project_feature.rb
@@ -109,6 +109,10 @@ class ProjectFeature < ApplicationRecord
pages_access_level == PUBLIC || pages_access_level == ENABLED && project.public?
end
+ def private_pages?
+ !public_pages?
+ end
+
private
# Validates builds and merge requests access level
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index bdac5b2a6a1..44cc051e94e 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -238,6 +238,7 @@ production: &base
access_control: false
# The location where pages are stored (default: shared/pages).
# path: shared/pages
+ # token: internal-api-token
# The domain under which the pages are served:
# http://group.example.com/project
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index ee8480122c4..22195c6a994 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -1628,5 +1628,44 @@ module API
class ClusterProject < Cluster
expose :project, using: Entities::BasicProjectDetails
end
+
+ module Pages
+ class ProjectLookupPath < Grape::Entity
+ expose :pages_https_only?, as: :https_only
+ expose :id, as: :project_id
+ expose :private_pages?, as: :access_control
+
+ expose :prefix do |project, opts|
+ if project.pages_root?
+ '/'
+ else
+ project.full_path.delete_prefix(opts[:prefix]) + '/'
+ end
+ end
+
+ expose :path do |project|
+ "#{project.public_pages_path}/"
+ end
+ end
+
+ class Domain < Grape::Entity
+ end
+
+ class PagesDomain < Domain
+ expose :certificate
+ expose :key
+
+ expose :lookup_paths, using: Pages::ProjectLookupPath do |domain|
+ [domain.project]
+ end
+ end
+
+ class NamespaceDomain < Domain
+ expose :lookup_paths, using: Pages::ProjectLookupPath do |group|
+ group.all_projects.with_pages.select(&:pages_deployed?)
+ .sort_by(&:pages_url).reverse
+ end
+ end
+ end
end
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 8a21d44b4bf..5c93021688b 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -212,13 +212,18 @@ module API
authenticate! unless %w[GET HEAD].include?(route.request_method)
end
- def authenticate_by_gitlab_shell_token!
+ def secret_token_param
input = params['secret_token']
input ||= Base64.decode64(headers[GITLAB_SHARED_SECRET_HEADER]) if headers.key?(GITLAB_SHARED_SECRET_HEADER)
-
input&.chomp!
+ end
+
+ def authenticate_by_gitlab_shell_token!
+ unauthorized! unless Devise.secure_compare(shell_secret_token, secret_token_param)
+ end
- unauthorized! unless Devise.secure_compare(secret_token, input)
+ def authenticate_by_gitlab_pages_token!
+ unauthorized! unless Devise.secure_compare(Gitlab.pages.token, secret_token_param)
end
def authenticated_with_full_private_access!
@@ -501,7 +506,7 @@ module API
@sudo_identifier ||= params[SUDO_PARAM] || env[SUDO_HEADER]
end
- def secret_token
+ def shell_secret_token
Gitlab::Shell.secret_token
end
diff --git a/lib/api/internals/pages.rb b/lib/api/internals/pages.rb
index a8631827b3d..1f0d5a99d83 100644
--- a/lib/api/internals/pages.rb
+++ b/lib/api/internals/pages.rb
@@ -3,15 +3,21 @@
module API
module Internals
class Pages < Grape::API
+ before { authenticate_by_gitlab_pages_token! }
+
namespace 'internals' do
params do
requires :host, type: String, desc: 'The Pages host'
end
get 'pages/query' do
- if namespace_name = find_namespace_name(params[:host])
- namespace_domain(namespace_name, params[:host].downcase)
- elsif domain = find_user_domain(params[:host])
- user_domain(domain)
+ if namespace = find_namespace(params[:host])
+ render namespace,
+ using: API::Entities::Pages::NamespaceDomain,
+ prefix: namespace.full_path
+ elsif domain = find_pages_domain(params[:host])
+ render domain,
+ using: API::Entities::Pages::PagesDomain,
+ prefix: domain.project.full_path
else
status :not_found
end
@@ -19,62 +25,19 @@ module API
end
helpers do
- def namespace_domain(namespace_name, host)
- lookup_paths = []
-
- if namespace = Namespace.find_by_full_path(namespace_name)
- namespace.all_projects.with_pages.each do |project|
- prefix = project.full_path.delete_prefix(namespace.full_path)
- lookup_paths << project_params(project, prefix)
- end
-
- lookup_paths << namespace_project_params(namespace, host, "")
- end
-
- status :ok
-
- { lookup_paths: lookup_paths.compact }
- end
-
- def user_domain(domain)
- lookup_paths = []
- lookup_paths << project_params(domain.project, "")
-
- status :ok
-
- {
- certificate: domain.certificate,
- key: domain.certificate_key,
- lookup_paths: lookup_paths.compact
- }
- end
-
def find_namespace_name(host)
host = host.downcase
gitlab_host = "." + ::Settings.pages.host.downcase
host.delete_suffix(gitlab_host) if host.ends_with?(gitlab_host)
end
- def find_user_domain(host)
- PagesDomain.find_by(domain: host.downcase)
- end
-
- def namespace_project_params(namespace, project_name, prefix)
- project = namespace.projects.with_pages.find_by(path: project_name)
- project_params(project, prefix)
+ def find_namespace(host)
+ namespace_name = find_namespace_name(host)
+ Namespace.find_by_full_path(namespace_name) if namespace_name
end
- def project_params(project, prefix)
- return unless project
- return unless project.pages_deployed?
-
- {
- https_only: project.pages_https_only?,
- project_id: project.project_id,
- access_control: !project.public_pages?,
- prefix: "#{prefix}/",
- path: "#{project.public_pages_path}/"
- }
+ def find_pages_domain(host)
+ PagesDomain.find_by(domain: host.downcase)
end
end
end