|
|
- require "kemal"
- require "../*"
- require "io"
- require "file"
- require "exception"
- require "crypto/bcrypt/password"
- require "uuid"
- require "uuid/json"
- require "socket/udp_socket"
- require "../../config"
-
- def fread(file) : String
- slc = Bytes.new file.size
- count = file.read slc
- String.new slc[0, count]
- end
-
- def authenticate(user : String, token : UUID) : (User | Nil)
- user_file : User | Nil = nil
- user_file = KVStore.access.fetch!("user/"+user)
- if user_file.nil?
- return nil
- end
- if nil == user_file.not_nil!.tokens.not_nil!.find{ |tok| token == tok}
- nil
- else
- user_file.not_nil!.password_hash = ""
- user_file
- end
- end
-
- def authenticate!(user : String, token : UUID) : User
- authenticate(user, token).not_nil!
- end
-
- def authenticate_admin!(user : String, token : UUID) : User
- user = authenticate(user, token).not_nil!
- if(user.type==UserType::Administrator)
- return user
- end
- raise "Administrator only"
- end
-
- ws "/socket/user/authenticate" do |socket|
- socket.on_message do |message|
- json = JSON.parse(message)
- if(authenticate(json["user"].to_s, UUID.new(json["api_token"].to_s)).nil?)
- json.as_h.["valid"]=JSON::Any.new false
- else
- json.as_h.["valid"]=JSON::Any.new true
- end
- socket.send json.to_json
- end
- end
-
- udp_listener = UDPSocket.new
- udp_listener.bind "0.0.0.0", 3000
- udp_mutex = Mutex.new
- (1..Statics.nb_udp_listeners).each do
- spawn do
- while true
- message : String | Nil = nil
- address : Socket::IPAddress | Nil = nil
- udp_mutex.synchronize do
- message, address = udp_listener.receive
- end
- json = JSON.parse(message.not_nil!)
- if(authenticate(json["user"].to_s, UUID.new(json["api_token"].to_s)).nil?)
- json.as_h.["valid"]=JSON::Any.new false
- else
- json.as_h.["valid"]=JSON::Any.new true
- end
- udp_mutex.synchronize do
- udp_listener.send json.to_json, address.not_nil!
- end
- end
- end
- end
-
-
-
-
- post "/login" do |context|
- user = User.from_json context.request.body.not_nil!
- user_file : User
- token : UUID | Nil = nil
- KVStore.access.transaction do |store|
- begin
- user_file = store.fetch! "user/"+user.email
- rescue ex
- halt context, status_code: 403, response: ex.to_s
- end
- if Crypto::Bcrypt::Password.new(user_file.password_hash.not_nil!) == user.password_hash.not_nil!
- else
- halt context, status_code: 403, response: "Invalid password"
- end
- if user_file.tokens.nil?
- user_file.tokens = Array(UUID).new
- end
- token = UUID.random()
- user_file.tokens.not_nil!<<token
- if user_file.tokens.not_nil!.size>5
- user_file.tokens = user_file.tokens.not_nil!.last(5)
- end
- store.push "user/"+user.email, user_file.to_json
- end
- context.response.content_type = "application/json"
- token.not_nil!.to_json
- end
-
- get "/logout" do |context|
- user = context.request.headers["user"]
-
- KVStore.access.transaction do |store|
- user_file = store.fetch!("user/"+user)
- user_file.tokens.not_nil!.delete(UUID.new(context.request.headers["api_token"]))
- store.push "user/"+user, user_file.to_json
- end
- context.response.content_type = "application/json"
- "OK".to_json
- end
-
- post "/logout-all" do |context|
- user : User
- begin
- user = authenticate!(context.request.headers["user"],UUID.new(context.request.headers["api_token"]))
- rescue ex
- halt context, status_code: 403, response: ex.to_s
- end
- KVStore.access.transaction do |store|
- user_file = store.fetch!("user/"+user.email)
- user_file.tokens=Array(UUID).new
- store.push "user/"+user_file.email, user_file.to_json
- end
- context.response.content_type = "application/json"
- "OK".to_json
- end
-
- post "/user" do |context|
- user = User.from_json context.request.body.not_nil!
- ph = user.password_hash
- user.tokens = Array(UUID).new
- user.invoices = Array(Invoice).new
- if ph.nil?
- halt context, status_code: 401, response: "No password provided"
- else
- user.password_hash=Crypto::Bcrypt::Password.create(ph,cost: 12).to_s
- end
- if Statics.email_regex.match(user.email)==nil
- halt context, status_code: 401, response: "Bad email address provided"
- end
- begin
- KVStore.access.transaction do |store|
- if store.fetch("user/"+user.email)!=nil
- raise IndexError.new
- end
- store.push "user/"+user.email, user.to_json
- end
- rescue ex
- halt context, status_code: 401, response: "Email address already in use"
- end
- context.response.content_type = "application/json"
- "OK".to_json
- end
-
- get "/user/tokens" do |context|
- user : User
- begin
- user = authenticate!(context.request.headers["user"],UUID.new(context.request.headers["api_token"]))
- rescue ex
- halt context, status_code: 403, response: ex.to_s
- end
- context.response.content_type = "application/json"
- user.tokens.to_json
- end
-
- get "/user/authenticate" do |context|
- user : User
- begin
- user = authenticate!(context.request.headers["user"],UUID.new(context.request.headers["api_token"]))
- rescue ex
- halt context, status_code: 403, response: ex.to_s
- end
- context.response.content_type = "application/json"
- "OK".to_json
- end
-
- get "/user/address" do |context|
- user : User
- begin
- user = authenticate!(context.request.headers["user"],UUID.new(context.request.headers["api_token"]))
- rescue ex
- halt context, status_code: 403, response: ex.to_s
- end
- context.response.content_type = "application/json"
- user.addresses.to_json
- end
-
- post "/user/address" do |context|
- user : User
- begin
- user = authenticate!(context.request.headers["user"],UUID.new(context.request.headers["api_token"]))
- rescue ex
- halt context, status_code: 403, response: ex.to_s
- end
- addresses = Array(Address).from_json(context.request.body.not_nil!).not_nil!
-
- KVStore.access.transaction do |store|
- user_file = store.fetch!("user/"+user.email)
- old_list=user_file.addresses
- if old_list.nil?
- else
- addresses=old_list+addresses
- end
- user_file.addresses=addresses
- store.push "user/"+user_file.email, user_file.to_json
- end
- context.response.content_type = "application/json"
- "OK".to_json
- end
-
- delete "/user/address" do |context|
- user = authenticate!(context.request.headers["user"],UUID.new(context.request.headers["api_token"]))
- addresses = Array(Address).from_json(context.request.body.not_nil!).not_nil!
-
- KVStore.access.transaction do |store|
- user_file = store.fetch!("user/"+user.email)
- old_list=user_file.addresses
- if old_list.nil?
- addresses=Array(Address).new
- else
- addresses=old_list.select do |v|
- isin=false
- addresses.each do |va|
- isin |= v==va
- end
- !isin
- end
- end
- user_file.addresses=addresses
- store.push "user/"+user_file.email, user_file.to_json
- end
- context.response.content_type = "application/json"
- "OK".to_json
- end
-
- get "/user" do |context|
- context.response.content_type = "application/json"
- user : User | Nil
- begin
- user = authenticate!(context.request.headers["user"],UUID.new(context.request.headers["api_token"]))
- rescue ex
- resp = String::Builder.build do |builder|
- if ENV["KEMAL_ENV"] == "test"
- ex.inspect_with_backtrace builder
- else
- ex.to_s builder
- end
- end
- halt context, status_code: 403, response: resp
- end
- user.not_nil!
- end
-
|