Overhauled response types.

ipc07
Luka Vandervelden 2019-11-22 22:55:12 +01:00
parent 297471b504
commit 2e5135656c
2 changed files with 137 additions and 37 deletions

View File

@ -6,16 +6,110 @@ require "ipc"
require "./user.cr" require "./user.cr"
module AuthD class AuthD::Response
class Response include JSON::Serializable
enum Type
Ok annotation MessageType
Malformed
InvalidCredentials
InvalidUser
UserNotFound # For UID-based GetUser requests.
AuthenticationError
end end
class_getter type = -1
macro inherited
def self.type
::AuthD::Response::Type::{{ @type.name.split("::").last.id }}
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 end
@ -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…
# itll 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

View File

@ -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