refact
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
module WarpEngine
|
||||
module AccessPolicyGuard
|
||||
private
|
||||
|
||||
def authorize_download!(asset:, subject:, request: nil)
|
||||
grant = WarpEngine.access_policy.authorize_download(asset: asset, subject: subject, request: request)
|
||||
raise WarpEngine::AccessDenied if grant.nil?
|
||||
grant
|
||||
rescue WarpEngine::AccessDenied
|
||||
raise
|
||||
rescue StandardError => e
|
||||
Rails.logger.error("[WarpEngine::AccessPolicy] #{e.class}: #{e.message}")
|
||||
raise WarpEngine::AccessDenied
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -11,6 +11,19 @@ module WarpEngine
|
||||
raw = JSON.parse(File.read(path), symbolize_names: true)
|
||||
raw.slice(*METADATA_KEYS)
|
||||
end
|
||||
|
||||
def parse_lua_metadata(source_path)
|
||||
metadata = {}
|
||||
File.foreach(source_path) do |line|
|
||||
break unless line.start_with?("--")
|
||||
parts = line[2..].split(":", 2)
|
||||
next if parts.length != 2
|
||||
key = parts[0].strip.downcase.to_sym
|
||||
value = parts[1].strip
|
||||
metadata[key] = value
|
||||
end
|
||||
metadata.slice(*METADATA_KEYS)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ module WarpEngine
|
||||
private
|
||||
|
||||
def update_or_create_software(attrs)
|
||||
software = WarpEngine::Software.unscoped.find_or_initialize_by(name: attrs[:name])
|
||||
software = WarpEngine::Software.find_or_initialize_by(name: attrs[:name])
|
||||
software.assign_attributes(attrs.except(:name))
|
||||
software.deleted_at = nil
|
||||
software.save!
|
||||
@@ -12,14 +12,14 @@ module WarpEngine
|
||||
end
|
||||
|
||||
def upsert_external_link(software_id, label, url)
|
||||
link = WarpEngine::ExternalLink.unscoped.find_or_initialize_by(software_id: software_id, label: label)
|
||||
link = WarpEngine::ExternalLink.find_or_initialize_by(software_id: software_id, label: label)
|
||||
link.url = url
|
||||
link.deleted_at = nil
|
||||
link.save!
|
||||
end
|
||||
|
||||
def create_release_if_not_exists(attrs)
|
||||
existing = WarpEngine::Release.unscoped.find_by(software_id: attrs[:software_id], version: attrs[:version])
|
||||
existing = WarpEngine::Release.find_by(software_id: attrs[:software_id], version: attrs[:version])
|
||||
return existing if existing
|
||||
|
||||
WarpEngine::Release.create!(attrs)
|
||||
@@ -27,7 +27,7 @@ module WarpEngine
|
||||
|
||||
def sync_release_assets(release, kind_paths)
|
||||
kind_paths.each do |kind, path|
|
||||
asset = WarpEngine::ReleaseAsset.unscoped.find_or_initialize_by(release_id: release.id, kind: kind)
|
||||
asset = WarpEngine::ReleaseAsset.find_or_initialize_by(release_id: release.id, kind: kind)
|
||||
asset.path = path
|
||||
asset.deleted_at = nil
|
||||
asset.save!
|
||||
|
||||
@@ -67,7 +67,7 @@ module WarpEngine
|
||||
private
|
||||
|
||||
def scope
|
||||
relation = WarpEngine::Software.order(:name).includes(releases: :release_assets)
|
||||
relation = WarpEngine::Software.kept.order(:name).includes(releases: :release_assets)
|
||||
relation = relation.where(name: name) if name
|
||||
relation = relation.where(platform: platform) if platform
|
||||
relation
|
||||
@@ -113,9 +113,7 @@ module WarpEngine
|
||||
def sorted(all) = all.sort_by { |release| [ release.created_at || Time.at(0), release.id ] }.reverse
|
||||
|
||||
def latest(all)
|
||||
candidates = all.reject { |release| release.version.to_s.start_with?("dev-") }
|
||||
candidates = all if candidates.empty?
|
||||
sorted(candidates).first
|
||||
Release.latest_non_dev(all)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,7 +11,7 @@ module WarpEngine
|
||||
end
|
||||
|
||||
def show(name)
|
||||
software = WarpEngine::Software.find_by!(name: name)
|
||||
software = WarpEngine::Software.kept.find_by!(name: name)
|
||||
expected = WarpEngine::Platform.find!(software.platform).expected_kinds
|
||||
|
||||
releases = software.releases.includes(:release_assets).order(updated_at: :desc)
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
require "warp_engine/access_denied"
|
||||
|
||||
module WarpEngine
|
||||
class DownloadService
|
||||
|
||||
class Denied < StandardError; end
|
||||
Denied = WarpEngine::AccessDenied
|
||||
|
||||
include AccessPolicyGuard
|
||||
|
||||
def locate(path:, ip:, user_agent:, referer:, subject: nil, request: nil)
|
||||
relative = path.to_s
|
||||
return nil unless storage.file?(relative)
|
||||
|
||||
asset = find_asset(relative)
|
||||
grant = authorize!(asset, subject, request)
|
||||
grant = authorize_download!(asset: asset, subject: subject, request: request)
|
||||
|
||||
log_download(relative, asset: asset, ip: ip, user_agent: user_agent, referer: referer, subject: subject)
|
||||
|
||||
@@ -31,18 +35,6 @@ module WarpEngine
|
||||
WarpEngine.storage
|
||||
end
|
||||
|
||||
def authorize!(asset, subject, request)
|
||||
grant = WarpEngine.access_policy.authorize_download(asset: asset, subject: subject, request: request)
|
||||
raise Denied if grant.nil?
|
||||
|
||||
grant
|
||||
rescue Denied
|
||||
raise
|
||||
rescue StandardError => e
|
||||
Rails.logger.error("[WarpEngine::AccessPolicy] #{e.class}: #{e.message}")
|
||||
raise Denied
|
||||
end
|
||||
|
||||
def find_asset(relative)
|
||||
WarpEngine::ReleaseAsset.for_relative_path(relative)
|
||||
end
|
||||
|
||||
@@ -30,7 +30,7 @@ module WarpEngine
|
||||
|
||||
safe_name = sanitize_name(uploaded_file.original_filename)
|
||||
target = dir.join(safe_name)
|
||||
raise ArgumentError, "Path escape" unless target.to_s.start_with?(base_path.to_s)
|
||||
ensure_within_base!(target)
|
||||
|
||||
IO.copy_stream(uploaded_file.to_io, target.to_s)
|
||||
target.relative_path_from(base_path).to_s
|
||||
@@ -53,7 +53,7 @@ module WarpEngine
|
||||
|
||||
safe_name = sanitize_name(new_name)
|
||||
new_full = full.parent.join(safe_name)
|
||||
raise ArgumentError, "Path escape" unless new_full.to_s.start_with?(base_path.to_s)
|
||||
ensure_within_base!(new_full)
|
||||
|
||||
full.rename(new_full)
|
||||
new_full.relative_path_from(base_path).to_s
|
||||
@@ -65,7 +65,7 @@ module WarpEngine
|
||||
|
||||
safe_name = sanitize_name(folder_name)
|
||||
new_dir = parent.join(safe_name)
|
||||
raise ArgumentError, "Path escape" unless new_dir.to_s.start_with?(base_path.to_s)
|
||||
ensure_within_base!(new_dir)
|
||||
|
||||
new_dir.mkdir
|
||||
new_dir.relative_path_from(base_path).to_s
|
||||
@@ -73,6 +73,10 @@ module WarpEngine
|
||||
|
||||
private
|
||||
|
||||
def ensure_within_base!(path)
|
||||
raise ArgumentError, "Path escape" unless path.to_s.start_with?(base_path.to_s)
|
||||
end
|
||||
|
||||
def safe_path!(relative_path)
|
||||
cleaned = relative_path.to_s.gsub("..", "").squeeze("/").gsub(%r{^/|/$}, "")
|
||||
full = base_path.join(cleaned)
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
require "warp_engine/access_denied"
|
||||
|
||||
module WarpEngine
|
||||
class FileService
|
||||
|
||||
include AccessPolicyGuard
|
||||
|
||||
def show(input, subject: nil)
|
||||
relative = input.path.to_s
|
||||
|
||||
@@ -21,19 +25,10 @@ module WarpEngine
|
||||
private
|
||||
|
||||
def authorize!(relative, subject)
|
||||
|
||||
return WarpEngine::Access::Grant::OPEN if WarpEngine::AccessPolicy.open?
|
||||
|
||||
asset = WarpEngine::ReleaseAsset.for_relative_path(relative)
|
||||
grant = WarpEngine.access_policy.authorize_download(asset: asset, subject: subject, request: nil)
|
||||
raise WarpEngine::DownloadService::Denied if grant.nil?
|
||||
|
||||
grant
|
||||
rescue WarpEngine::DownloadService::Denied
|
||||
raise
|
||||
rescue StandardError => e
|
||||
Rails.logger.error("[WarpEngine::AccessPolicy] #{e.class}: #{e.message}")
|
||||
raise WarpEngine::DownloadService::Denied
|
||||
authorize_download!(asset: asset, subject: subject, request: nil)
|
||||
end
|
||||
|
||||
def storage
|
||||
|
||||
@@ -10,7 +10,7 @@ module WarpEngine
|
||||
remote_ids = remote_repos.map(&:id)
|
||||
|
||||
remote_repos.each do |remote|
|
||||
record = Pipeline.unscoped.find_or_initialize_by(woodpecker_repo_id: remote.id)
|
||||
record = Pipeline.find_or_initialize_by_remote_repo_id(remote.id)
|
||||
|
||||
was_new = record.new_record?
|
||||
record.assign_attributes(
|
||||
@@ -27,7 +27,7 @@ module WarpEngine
|
||||
results[was_new ? :created : :updated] << record
|
||||
end
|
||||
|
||||
Pipeline.where.not(woodpecker_repo_id: remote_ids).find_each do |orphan|
|
||||
Pipeline.kept.where.not(woodpecker_repo_id: remote_ids).find_each do |orphan|
|
||||
orphan.update!(active: false) if orphan.active?
|
||||
results[:deactivated] << orphan
|
||||
end
|
||||
@@ -42,7 +42,7 @@ module WarpEngine
|
||||
|
||||
def deactivate(repo_id)
|
||||
@ci.deactivate_repo(repo_id)
|
||||
record = Pipeline.find_by!(woodpecker_repo_id: repo_id)
|
||||
record = Pipeline.kept.find_by!(woodpecker_repo_id: repo_id)
|
||||
record.update!(active: false)
|
||||
end
|
||||
|
||||
@@ -50,7 +50,7 @@ module WarpEngine
|
||||
|
||||
def sync_single(repo_id)
|
||||
remote = @ci.repo(repo_id)
|
||||
record = Pipeline.unscoped.find_or_initialize_by(woodpecker_repo_id: repo_id)
|
||||
record = Pipeline.find_or_initialize_by_remote_repo_id(repo_id)
|
||||
record.assign_attributes(
|
||||
repo_name: remote.name, repo_owner: remote.owner,
|
||||
active: remote.active?, deleted_at: nil
|
||||
@@ -63,7 +63,7 @@ module WarpEngine
|
||||
def assign_platform(record, repo_name)
|
||||
return unless record.platform.blank? || record.platform == Pipeline::UNKNOWN_PLATFORM
|
||||
|
||||
sw = Software.find_by(name: repo_name)
|
||||
sw = Software.kept.find_by(name: repo_name)
|
||||
record.platform = sw&.platform || Pipeline::UNKNOWN_PLATFORM
|
||||
record.software = sw if sw
|
||||
end
|
||||
|
||||
@@ -21,19 +21,6 @@ module WarpEngine
|
||||
def parse_metadata(versioned)
|
||||
parse_lua_metadata(full_path("#{versioned}.lua"))
|
||||
end
|
||||
|
||||
def parse_lua_metadata(source_path)
|
||||
metadata = {}
|
||||
File.foreach(source_path) do |line|
|
||||
break unless line.start_with?("--")
|
||||
parts = line[2..].split(":", 2)
|
||||
next if parts.length != 2
|
||||
key = parts[0].strip.downcase.to_sym
|
||||
value = parts[1].strip
|
||||
metadata[key] = value
|
||||
end
|
||||
metadata.slice(*MetadataParsing::METADATA_KEYS)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,22 +36,28 @@ module WarpEngine
|
||||
pipelines = pipelines_for_token(application_token)
|
||||
return { rotated: false, reason: "no pipelines" } if pipelines.empty?
|
||||
|
||||
new_token = ApplicationToken.create!(
|
||||
name: "#{application_token.name} (rotated #{Date.current})",
|
||||
owner_id: application_token.owner_id,
|
||||
owner_type: application_token.owner_type,
|
||||
scopes: application_token.scopes,
|
||||
expires_at: application_token.expires_at,
|
||||
unrestricted: application_token.unrestricted?
|
||||
)
|
||||
new_token = nil
|
||||
ActiveRecord::Base.transaction do
|
||||
new_token = ApplicationToken.create!(
|
||||
name: "#{application_token.name} (rotated #{Date.current})",
|
||||
owner_id: application_token.owner_id,
|
||||
owner_type: application_token.owner_type,
|
||||
scopes: application_token.scopes,
|
||||
expires_at: application_token.expires_at,
|
||||
unrestricted: application_token.unrestricted?
|
||||
)
|
||||
application_token.soft_delete!
|
||||
end
|
||||
|
||||
result = provision(new_token.plain_token, pipelines: pipelines)
|
||||
|
||||
if result[:synced].any?
|
||||
application_token.revoke!
|
||||
{ rotated: true, new_token: new_token, sync_result: result }
|
||||
else
|
||||
new_token.revoke!
|
||||
ActiveRecord::Base.transaction do
|
||||
application_token.restore!
|
||||
new_token.soft_delete!
|
||||
end
|
||||
{ rotated: false, reason: "all pipelines failed", sync_result: result }
|
||||
end
|
||||
end
|
||||
@@ -60,7 +66,7 @@ module WarpEngine
|
||||
if application_token.unrestricted?
|
||||
Pipeline.active.to_a
|
||||
else
|
||||
software_ids = Software.where(
|
||||
software_ids = Software.kept.where(
|
||||
owner_type: application_token.owner_type,
|
||||
owner_id: application_token.owner_id
|
||||
).pluck(:id)
|
||||
|
||||
@@ -3,13 +3,15 @@ module WarpEngine
|
||||
include SoftwareResponseBuilder
|
||||
|
||||
def index(subject: nil)
|
||||
software = visible_scope(subject).includes(:external_links, :software_images)
|
||||
.where(highlighted: true)
|
||||
.order(id: :desc)
|
||||
.first
|
||||
software = visible_scope(subject)
|
||||
.includes(releases: :release_assets)
|
||||
.includes(:external_links, :software_images)
|
||||
.where(highlighted: true)
|
||||
.order(id: :desc)
|
||||
.first
|
||||
return nil unless software
|
||||
|
||||
releases = WarpEngine::Release.includes(:release_assets).where(software_id: software.id).to_a
|
||||
releases = software.releases.to_a
|
||||
build_response(software, releases, download_counts_for(releases.map(&:id)), subject: subject)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ module WarpEngine
|
||||
|
||||
def build_response(software, releases, download_counts, subject: nil)
|
||||
sorted = releases.sort_by { |r| r.created_at || Time.at(0) }.reverse
|
||||
latest = sorted.reject { |r| r.version.to_s.start_with?("dev-") }.first
|
||||
latest = Release.latest_non_dev(releases)
|
||||
|
||||
web_playable = latest if latest&.release_assets&.any? { |a| a.kind == "html" }
|
||||
total_downloads = releases.sum { |r| download_counts.fetch(r.id, 0) }
|
||||
@@ -36,7 +36,7 @@ module WarpEngine
|
||||
|
||||
def download_counts_for(release_ids)
|
||||
return {} if release_ids.empty?
|
||||
WarpEngine::Download.where(release_id: release_ids).group(:release_id).count
|
||||
WarpEngine::Download.kept.where(release_id: release_ids).group(:release_id).count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user