Overhauled response types.
parent
297471b504
commit
2e5135656c
149
src/authd.cr
149
src/authd.cr
|
@ -6,17 +6,111 @@ require "ipc"
|
||||||
|
|
||||||
require "./user.cr"
|
require "./user.cr"
|
||||||
|
|
||||||
module AuthD
|
class AuthD::Response
|
||||||
class Response
|
include JSON::Serializable
|
||||||
enum Type
|
|
||||||
Ok
|
annotation MessageType
|
||||||
Malformed
|
end
|
||||||
InvalidCredentials
|
|
||||||
InvalidUser
|
class_getter type = -1
|
||||||
UserNotFound # For UID-based GetUser requests.
|
|
||||||
AuthenticationError
|
macro inherited
|
||||||
|
def self.type
|
||||||
|
::AuthD::Response::Type::{{ @type.name.split("::").last.id }}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
macro initialize(*properties)
|
||||||
|
def initialize(
|
||||||
|
{% for value in properties %}
|
||||||
|
@{{value.id}}{% if value != properties.last %},{% end %}
|
||||||
|
{% end %}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
Type::{{ @type.name.split("::").last.id }}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Error < Response
|
||||||
|
property reason : String?
|
||||||
|
|
||||||
|
initialize :reason
|
||||||
|
end
|
||||||
|
|
||||||
|
class Token < Response
|
||||||
|
property token : String
|
||||||
|
|
||||||
|
initialize :token
|
||||||
|
end
|
||||||
|
|
||||||
|
class User < Response
|
||||||
|
property user : Passwd::User
|
||||||
|
|
||||||
|
initialize :user
|
||||||
|
end
|
||||||
|
|
||||||
|
class UserAdded < Response
|
||||||
|
property user : Passwd::User
|
||||||
|
|
||||||
|
initialize :user
|
||||||
|
end
|
||||||
|
|
||||||
|
class UserEdited < Response
|
||||||
|
property uid : Int32
|
||||||
|
|
||||||
|
initialize :uid
|
||||||
|
end
|
||||||
|
|
||||||
|
# This creates a Request::Type enumeration. One entry for each request type.
|
||||||
|
{% begin %}
|
||||||
|
enum Type
|
||||||
|
{% for ivar in @type.subclasses %}
|
||||||
|
{% klass = ivar.name %}
|
||||||
|
{% name = ivar.name.split("::").last.id %}
|
||||||
|
|
||||||
|
{% a = ivar.annotation(MessageType) %}
|
||||||
|
|
||||||
|
{% if a %}
|
||||||
|
{% value = a[0] %}
|
||||||
|
{{ name }} = {{ value }}
|
||||||
|
{% else %}
|
||||||
|
{{ name }}
|
||||||
|
{% end %}
|
||||||
|
{% end %}
|
||||||
|
end
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
# This is an array of all requests types.
|
||||||
|
{% begin %}
|
||||||
|
class_getter requests = [
|
||||||
|
{% for ivar in @type.subclasses %}
|
||||||
|
{% klass = ivar.name %}
|
||||||
|
|
||||||
|
{{klass}},
|
||||||
|
{% end %}
|
||||||
|
]
|
||||||
|
{% end %}
|
||||||
|
|
||||||
|
def self.from_ipc(message : IPC::Message)
|
||||||
|
payload = String.new message.payload
|
||||||
|
type = Type.new message.type.to_i
|
||||||
|
|
||||||
|
begin
|
||||||
|
request = requests.find(&.type.==(type)).try &.from_json(payload)
|
||||||
|
rescue e : JSON::ParseException
|
||||||
|
raise Exception.new "malformed request"
|
||||||
|
end
|
||||||
|
|
||||||
|
request
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class IPC::Connection
|
||||||
|
def send(response : AuthD::Response)
|
||||||
|
send response.type.to_u8, response.to_json
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class AuthD::Request
|
class AuthD::Request
|
||||||
|
@ -154,10 +248,10 @@ module AuthD
|
||||||
def get_token?(login : String, password : String) : String?
|
def get_token?(login : String, password : String) : String?
|
||||||
send Request::GetToken.new login, password
|
send Request::GetToken.new login, password
|
||||||
|
|
||||||
response = read
|
response = Response.from_ipc read
|
||||||
|
|
||||||
if response.type == Response::Type::Ok.value.to_u8
|
if response.is_a?(Response::Token)
|
||||||
String.new response.payload
|
response.token
|
||||||
else
|
else
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
@ -166,10 +260,10 @@ module AuthD
|
||||||
def get_user?(login : String, password : String) : Passwd::User?
|
def get_user?(login : String, password : String) : Passwd::User?
|
||||||
send Request::GetUserByCredentials.new login, password
|
send Request::GetUserByCredentials.new login, password
|
||||||
|
|
||||||
response = read
|
response = Response.from_ipc read
|
||||||
|
|
||||||
if response.type == Response::Type::Ok.value.to_u8
|
if response.is_a? Response::User
|
||||||
Passwd::User.from_json String.new response.payload
|
response.user
|
||||||
else
|
else
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
@ -203,14 +297,17 @@ module AuthD
|
||||||
def add_user(login : String, password : String) : Passwd::User | Exception
|
def add_user(login : String, password : String) : Passwd::User | Exception
|
||||||
send Request::AddUser.new @key, login, password
|
send Request::AddUser.new @key, login, password
|
||||||
|
|
||||||
response = read
|
response = Response.from_ipc read
|
||||||
|
|
||||||
payload = String.new response.payload
|
case response
|
||||||
case Response::Type.new response.type.to_i
|
when Response::UserAdded
|
||||||
when Response::Type::Ok
|
response.user
|
||||||
Passwd::User.from_json payload
|
when Response::Error
|
||||||
|
Exception.new response.reason
|
||||||
else
|
else
|
||||||
Exception.new payload
|
# Should not happen in serialized connections, but…
|
||||||
|
# it’ll happen if you run several requests at once.
|
||||||
|
Exception.new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -222,13 +319,15 @@ module AuthD
|
||||||
|
|
||||||
send request
|
send request
|
||||||
|
|
||||||
response = read
|
response = Response.from_ipc read
|
||||||
|
|
||||||
case Response::Type.new response.type.to_i
|
case response
|
||||||
when Response::Type::Ok
|
when Response::UserEdited
|
||||||
true
|
true
|
||||||
|
when Response::Error
|
||||||
|
Exception.new response.reason
|
||||||
else
|
else
|
||||||
Exception.new String.new response.payload
|
Exception.new "???"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
25
src/main.cr
25
src/main.cr
|
@ -65,47 +65,48 @@ IPC::Service.new "auth" do |event|
|
||||||
user = passwd.get_user request.login, request.password
|
user = passwd.get_user request.login, request.password
|
||||||
|
|
||||||
if user.nil?
|
if user.nil?
|
||||||
client.send Response::Type::InvalidCredentials.value.to_u8, ""
|
client.send Response::Error.new "invalid credentials"
|
||||||
|
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
client.send Response::Type::Ok.value.to_u8,
|
token = JWT.encode user.to_h, authd_jwt_key, JWT::Algorithm::HS256
|
||||||
JWT.encode user.to_h, authd_jwt_key, JWT::Algorithm::HS256
|
|
||||||
|
client.send Response::Token.new token
|
||||||
when Request::AddUser
|
when Request::AddUser
|
||||||
if request.shared_key != authd_jwt_key
|
if request.shared_key != authd_jwt_key
|
||||||
client.send Response::Type::AuthenticationError, "Invalid authentication key."
|
client.send Response::Error.new "invalid authentication key"
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
if passwd.user_exists? request.login
|
if passwd.user_exists? request.login
|
||||||
client.send Response::Type::InvalidUser, "Another user with the same login already exists."
|
client.send Response::Error.new "login already used"
|
||||||
|
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
user = passwd.add_user request.login, request.password
|
user = passwd.add_user request.login, request.password
|
||||||
|
|
||||||
client.send Response::Type::Ok, user.sanitize!.to_json
|
client.send Response::UserAdded.new user
|
||||||
when Request::GetUserByCredentials
|
when Request::GetUserByCredentials
|
||||||
user = passwd.get_user request.login, request.password
|
user = passwd.get_user request.login, request.password
|
||||||
|
|
||||||
if user
|
if user
|
||||||
client.send Response::Type::Ok, user.sanitize!.to_json
|
client.send Response::User.new user
|
||||||
else
|
else
|
||||||
client.send Response::Type::UserNotFound, ""
|
client.send Response::Error.new "user not found"
|
||||||
end
|
end
|
||||||
when Request::GetUser
|
when Request::GetUser
|
||||||
user = passwd.get_user request.uid
|
user = passwd.get_user request.uid
|
||||||
|
|
||||||
if user
|
if user
|
||||||
client.send Response::Type::Ok, user.sanitize!.to_json
|
client.send Response::User.new user
|
||||||
else
|
else
|
||||||
client.send Response::Type::UserNotFound, ""
|
client.send Response::Error.new "user not found"
|
||||||
end
|
end
|
||||||
when Request::ModUser
|
when Request::ModUser
|
||||||
if request.shared_key != authd_jwt_key
|
if request.shared_key != authd_jwt_key
|
||||||
client.send Response::Type::AuthenticationError, "Invalid authentication key."
|
client.send Response::Error.new "invalid authentication key"
|
||||||
next
|
next
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -115,7 +116,7 @@ IPC::Service.new "auth" do |event|
|
||||||
|
|
||||||
passwd.mod_user request.uid, password_hash: password_hash
|
passwd.mod_user request.uid, password_hash: password_hash
|
||||||
|
|
||||||
client.send Response::Type::Ok, ""
|
client.send Response::UserEdited.new request.uid
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue