authd/src/authd.cr

181 lines
3.2 KiB
Crystal

require "jwt"
require "ipc"
require "./user.cr"
module AuthD
enum RequestTypes
GetToken
AddUser
GetUser
GetUserByCredentials
ModUser # Edit user attributes.
end
enum ResponseTypes
Ok
MalformedRequest
InvalidCredentials
InvalidUser
UserNotFound # For UID-based GetUser requests.
AuthenticationError
end
class GetTokenRequest
JSON.mapping({
# FIXME: Rename to "login" for consistency.
login: String,
password: String
})
end
class AddUserRequest
JSON.mapping({
# Only clients that have the right shared key will be allowed
# to create users.
shared_key: String,
login: String,
password: String,
uid: Int32?,
gid: Int32?,
home: String?,
shell: String?
})
end
class GetUserRequest
JSON.mapping({
uid: Int32
})
end
class GetUserByCredentialsRequest
JSON.mapping({
login: String,
password: String
})
end
class ModUserRequest
JSON.mapping({
shared_key: String,
uid: Int32,
password: String?,
avatar: String?
})
end
class Client < IPC::Connection
property key : String
def initialize
@key = ""
initialize "auth"
end
def get_token?(login : String, password : String) : String?
send RequestTypes::GetToken, {
:login => login,
:password => password
}.to_json
response = read
if response.type == ResponseTypes::Ok.value.to_u8
String.new response.payload
else
nil
end
end
def get_user?(login : String, password : String) : Passwd::User?
send RequestTypes::GetUserByCredentials, {
:login => login,
:password => password
}.to_json
response = read
if response.type == ResponseTypes::Ok.value.to_u8
Passwd::User.from_json String.new response.payload
else
nil
end
end
def get_user?(uid : Int32)
send RequestTypes::GetUser, {:uid => uid}.to_json
response = read
if response.type == ResponseTypes::Ok.value.to_u8
User.from_json String.new response.payload
else
nil
end
end
def send(type : RequestTypes, payload)
send type.value.to_u8, payload
end
def decode_token(token)
user, meta = JWT.decode token, @key, JWT::Algorithm::HS256
user = Passwd::User.from_json user.to_json
{user, meta}
end
# FIXME: Extra options may be useful to implement here.
def add_user(login : String, password : String) : Passwd::User | Exception
send RequestTypes::AddUser, {
:shared_key => @key,
:login => login,
:password => password
}.to_json
response = read
payload = String.new response.payload
case ResponseTypes.new response.type.to_i
when ResponseTypes::Ok
Passwd::User.from_json payload
else
Exception.new payload
end
end
def mod_user(uid : Int32, password : String? = nil, avatar : String? = nil) : Bool | Exception
payload = Hash(String, String|Int32).new
payload["uid"] = uid
payload["shared_key"] = @key
password.try do |password|
payload["password"] = password
end
avatar.try do |avatar|
payload["avatar"] = avatar
end
send RequestTypes::ModUser, payload.to_json
response = read
case ResponseTypes.new response.type.to_i
when ResponseTypes::Ok
true
else
Exception.new String.new response.payload
end
end
end
end