Files
ubicloud/clover_api.rb
Jeremy Evans a5be919419 Combine UBID and name segments in API paths
Previously, there were separate API paths for accessing objects, one
by name and one by UBID.  Example:

* /project/{project_id}/location/{location}/vm/id/{vm_id}
* /project/{project_id}/location/{location}/vm/{vm_name}

This duplication causes problems, so this commit collapses them into

* /project/{project_id}/location/{location}/vm/{vm_name_or_id}

To avoid potential ambiguity, as names can also be 26 base32
characters, UBIDs used in paths must now be prefixed by an
underscore.  The matcher used for matching either name or UBID is
CloverApi::NAME_OR_UBID, a regexp restricting to only matching
valid names, and UBIDs prefixed with an understcore.

This simplifies some code, though to handle invalid POST and DELETE
requests, this adds fallback code to most of the routes, to support
returning 204 instead of 404 responses, as that is what the specs
require.

While here, change the Sequel object retrieval style from:

.where(location: @location).where { {Sequel[:private_subnet][:name] => ps_name} }.first

to:

.first(:location => @location, Sequel[:private_subnet][:name] => ps_name)

This avoids creating as many intermediate datasets, and avoids using
virtual rows unnecessarily.
2024-10-24 08:48:59 -07:00

96 lines
2.2 KiB
Ruby
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# frozen_string_literal: true
require "roda"
require_relative "model"
class CloverApi < Roda
include CloverBase
plugin :default_headers,
"Content-Type" => "application/json"
plugin :hash_branches
plugin :json
plugin :json_parser
NAME_OR_UBID = /([a-z0-9](?:[a-z0-9\-]{0,61}[a-z0-9])?)|_([a-z0-9]{26})/
autoload_routes("api")
plugin :not_found do
response["Content-Type"] = "application/json"
{
error: {
code: 404,
type: "ResourceNotFound",
message: "Sorry, we couldnt find the resource youre looking for."
}
}.to_json
end
plugin :error_handler do |e|
response["Content-Type"] = "application/json"
error = parse_error(e)
{error: error}.to_json
end
plugin :rodauth do
enable :argon2, :json, :jwt, :active_sessions, :login
only_json? true
use_jwt? true
# Converting rodauth error response to the common error format of the API
json_response_body do |hash|
# In case of an error, rodauth returns the error in the following format
# {
# (required) "error": "There was an error logging in"
# (optional) "field-error": [
# "password",
# "invalid password"
# ]
# }
if json_response_error?
error_message = hash["error"]
type, code = case error_message
when "There was an error logging in"
["InvalidCredentials", 401]
when "invalid JWT format or claim in Authorization header"
["InvalidRequest", 400]
when "Please login to continue"
["LoginRequired", 401]
else
# :nocov:
["AuthenticationError", 401]
# :nocov:
end
hash.clear
hash["error"] = {
"code" => code,
"type" => type,
"message" => error_message
}
end
hash.to_json
end
hmac_secret Config.clover_session_secret
jwt_secret Config.clover_session_secret
argon2_secret { Config.clover_session_secret }
require_bcrypt? false
end
route do |r|
r.rodauth
rodauth.check_active_session
rodauth.require_authentication
@current_user = Account[rodauth.session_value]
r.hash_branches("")
end
end