From 29c8bb368f3e53543084e7f6d421983cdecd24d6 Mon Sep 17 00:00:00 2001 From: "Joseph.Roy" Date: Thu, 14 Dec 2023 17:30:29 +0000 Subject: [PATCH] add file transfer feature and add more jwt functionality --- auth/Gemfile | 2 + auth/auth.rb | 97 +++++++++++++++---------------------- auth/cryptography.rb | 3 +- auth/database_queries.rb | 45 ++++++++++++++--- auth/initialize_database.rb | 24 ++++++--- auth/post.rb | 61 ++++++++++++++++++----- 6 files changed, 146 insertions(+), 86 deletions(-) diff --git a/auth/Gemfile b/auth/Gemfile index 4b410b5..5d8e98d 100644 --- a/auth/Gemfile +++ b/auth/Gemfile @@ -12,5 +12,7 @@ gem 'sqlite3' gem 'bcrypt' gem 'securerandom' gem 'json' +gem 'multipart-post' + # bundle install \ No newline at end of file diff --git a/auth/auth.rb b/auth/auth.rb index 2250562..c23dd6f 100644 --- a/auth/auth.rb +++ b/auth/auth.rb @@ -2,6 +2,7 @@ require_relative "initialize_database" require_relative "database_queries" require_relative "cryptography" +require_relative "tokens" require 'sinatra' @@ -9,6 +10,10 @@ require 'json' require 'sqlite3' require 'jwt' +TOKEN_SECRET = 'WChX-tQWbGbj_pGJQREoFAZGC9JWh58KSk8O7KPj-P8Nd-J88g3eSFDVuNe6zddj0ZB3yxjm_IuPNPyLhiSnxlWHImqXR6ajh3OzrzYm0bNb3f5C4IAScphyEdAfYGMcM-HvYOXxxxp5u5mryfiV3JH1CTqL1CzGyO8df7zUpRKXEXZ5SKmUvhfLU0XKCR_28FAZUgPCAi3GywkDDsH0by68j33BU5cnMT8KiEkHOX4wVUVDQc85_AuE7fN3ji_WkhnDCSLXU9dBCcXM3ziFFeX0RbvIRDG0vKdzwt4TOr4Jws7NP9w11GrUGDFKARZqvT7FTxwxO3MM-mmjb2xyGg' + +set :public_folder, DATA_LOCATION + FILE_STORAGE_LOCATION + #puts generate_random_string(256) @@ -68,85 +73,59 @@ post '/auth/reauthenticate' do reauth_token = Regexp.last_match(1) - hmac_secret = 'WChX-tQWbGbj_pGJQREoFAZGC9JWh58KSk8O7KPj-P8Nd-J88g3eSFDVuNe6zddj0ZB3yxjm_IuPNPyLhiSnxlWHImqXR6ajh3OzrzYm0bNb3f5C4IAScphyEdAfYGMcM-HvYOXxxxp5u5mryfiV3JH1CTqL1CzGyO8df7zUpRKXEXZ5SKmUvhfLU0XKCR_28FAZUgPCAi3GywkDDsH0by68j33BU5cnMT8KiEkHOX4wVUVDQc85_AuE7fN3ji_WkhnDCSLXU9dBCcXM3ziFFeX0RbvIRDG0vKdzwt4TOr4Jws7NP9w11GrUGDFKARZqvT7FTxwxO3MM-mmjb2xyGg' - begin # Verify the token using the secret key - decoded_token = JWT.decode(reauth_token, hmac_secret, true, algorithm: 'HS256') + decoded_token = JWT.decode(reauth_token, TOKEN_SECRET, true, algorithm: 'HS256') # At this point, the token is valid # You can access the claims inside the 'decoded_token' variable uid = decoded_token.first['uid'] - + # Your reauthentication logic here... # Return a response (replace with your own logic) - { reply: get_jwt(uid) }.to_json + { jwt: get_jwt(uid) }.to_json rescue JWT::DecodeError status 401 return { reply: 'Unauthorized Access. Invalid token.' }.to_json end end -def get_reauth_jwt (user_id) - #claims = get_claims user_id +post '/upload' do - payload = { - sub: 'reauthentication' , - admin: check_if_user_is_admin(user_id), - iss: 'roysathome.net', - uid: user_id, #Example id - iat: Time.now.to_i, - exp: Time.now.to_i + 3600 - } + authorization_header = request.env['HTTP_AUTHORIZATION'] - hmac_secret = 'WChX-tQWbGbj_pGJQREoFAZGC9JWh58KSk8O7KPj-P8Nd-J88g3eSFDVuNe6zddj0ZB3yxjm_IuPNPyLhiSnxlWHImqXR6ajh3OzrzYm0bNb3f5C4IAScphyEdAfYGMcM-HvYOXxxxp5u5mryfiV3JH1CTqL1CzGyO8df7zUpRKXEXZ5SKmUvhfLU0XKCR_28FAZUgPCAi3GywkDDsH0by68j33BU5cnMT8KiEkHOX4wVUVDQc85_AuE7fN3ji_WkhnDCSLXU9dBCcXM3ziFFeX0RbvIRDG0vKdzwt4TOr4Jws7NP9w11GrUGDFKARZqvT7FTxwxO3MM-mmjb2xyGg' - return JWT.encode payload, hmac_secret, 'HS256' -#data: {time: 'now', help: 'no'}.to_json -end - -def get_jwt (user_id) - claims = get_claims user_id - - payload = { - sub: 'authentication' , - admin: check_if_user_is_admin(user_id), - iss: 'roysathome.net', - uid: user_id, #Example id - iat: Time.now.to_i, - exp: Time.now.to_i + 60, - claims: claims - } - - hmac_secret = 'WChX-tQWbGbj_pGJQREoFAZGC9JWh58KSk8O7KPj-P8Nd-J88g3eSFDVuNe6zddj0ZB3yxjm_IuPNPyLhiSnxlWHImqXR6ajh3OzrzYm0bNb3f5C4IAScphyEdAfYGMcM-HvYOXxxxp5u5mryfiV3JH1CTqL1CzGyO8df7zUpRKXEXZ5SKmUvhfLU0XKCR_28FAZUgPCAi3GywkDDsH0by68j33BU5cnMT8KiEkHOX4wVUVDQc85_AuE7fN3ji_WkhnDCSLXU9dBCcXM3ziFFeX0RbvIRDG0vKdzwt4TOr4Jws7NP9w11GrUGDFKARZqvT7FTxwxO3MM-mmjb2xyGg' - return JWT.encode payload, hmac_secret, 'HS256' -end - -def get_claims (user_id) - puts "Getting claims for #{user_id}" - db = SQLite3::Database.new('./database/auth.db') - results = db.execute(' - SELECT C.claim - FROM users U - INNER JOIN user_claims UC ON U.id = UC.user_id - INNER JOIN claims C ON UC.claim_id = U.id - WHERE u.id = ? - ', user_id) - - - claims_list = [] - - if results.empty? - puts 'No claims found.' - else - results.each do |column| - claim = column[0] - claims_list << claim - end + unless authorization_header && authorization_header.match(/^Bearer (.+)/) + status 401 + return { reply: 'Unauthorized Access. Token missing or invalid.' }.to_json end - return claims_list + token = Regexp.last_match(1) + + begin + # Verify the token using the secret key + decoded_token = JWT.decode(token, TOKEN_SECRET, true, algorithm: 'HS256') + + unless decoded_token.first['claims'].include? 'is_machine' + status 401 + return { reply: 'Unauthorized Access.' }.to_json + end + + # Access the uploaded file through the params hash + file = params[:file] + + # Save the file to the 'uploads' folder + path = "#{DATA_LOCATION}#{FILE_STORAGE_LOCATION}/example.txt" + File.open(path, 'wb') do |f| + f.write(file[:tempfile].read) + end + + "File uploaded successfully: #{file[:filename]}" + rescue JWT::DecodeError + status 401 + return { reply: 'Unauthorized Access. Invalid token.' }.to_json + end end # Run the application diff --git a/auth/cryptography.rb b/auth/cryptography.rb index f2c871a..750ae38 100644 --- a/auth/cryptography.rb +++ b/auth/cryptography.rb @@ -17,4 +17,5 @@ end def generate_random_string(length) SecureRandom.urlsafe_base64(length) - end \ No newline at end of file +end + diff --git a/auth/database_queries.rb b/auth/database_queries.rb index d2669b1..1a533a2 100644 --- a/auth/database_queries.rb +++ b/auth/database_queries.rb @@ -1,7 +1,12 @@ require 'sqlite3' +DATA_LOCATION = './data' +DATABASE_SUBPATH = '/database' +DATABASE_NAME = '/auth.db' +FILE_STORAGE_LOCATION = '/files' + def create_new_user(username, password, is_admin) - db = SQLite3::Database.new('./database/auth.db') + db = SQLite3::Database.new( DATA_LOCATION + DATABASE_SUBPATH + DATABASE_NAME ) db.execute(' INSERT INTO users (username, hashed_password, is_admin) @@ -10,7 +15,7 @@ def create_new_user(username, password, is_admin) end def check_if_user_exists(username) - db = SQLite3::Database.new('./database/auth.db') + db = SQLite3::Database.new( DATA_LOCATION + DATABASE_SUBPATH + DATABASE_NAME ) result = db.get_first_value('SELECT COUNT(*) FROM users WHERE username = ?', username.downcase) @@ -22,7 +27,7 @@ def check_if_user_exists(username) end def check_if_user_is_admin(user_id) - db = SQLite3::Database.new('./database/auth.db') + db = SQLite3::Database.new( DATA_LOCATION + DATABASE_SUBPATH + DATABASE_NAME ) result = db.get_first_value('SELECT is_admin FROM users WHERE id = ?', user_id) @@ -35,7 +40,7 @@ end def get_user_id(username) - db = SQLite3::Database.new('./database/auth.db') + db = SQLite3::Database.new( DATA_LOCATION + DATABASE_SUBPATH + DATABASE_NAME ) user_id = db.get_first_value(' SELECT id @@ -48,7 +53,7 @@ def get_user_id(username) end def get_user_hashed_password(user_id) - db = SQLite3::Database.new('./database/auth.db') + db = SQLite3::Database.new( DATA_LOCATION + DATABASE_SUBPATH + DATABASE_NAME ) password_hash = db.get_first_value(' SELECT hashed_password @@ -61,11 +66,37 @@ def get_user_hashed_password(user_id) end def update_user_password(user_id, password) - db = SQLite3::Database.new('./database/auth.db') + db = SQLite3::Database.new( DATA_LOCATION + DATABASE_SUBPATH + DATABASE_NAME ) db.execute(' UPDATE users SET hashed_password = ?, salt = ? WHERE id = ? ', [hash_password, salt, user_id]) -end \ No newline at end of file +end + +def get_claims (user_id) + puts "Getting claims for #{user_id}" + db = SQLite3::Database.new( DATA_LOCATION + DATABASE_SUBPATH + DATABASE_NAME ) + results = db.execute(' + SELECT C.claim + FROM users U + INNER JOIN user_claims UC ON U.id = UC.user_id + INNER JOIN claims C ON UC.claim_id = U.id + WHERE u.id = ? + ', user_id) + + + claims_list = [] + + if results.empty? + puts 'No claims found.' + else + results.each do |column| + claim = column[0] + claims_list << claim + end + end + + return claims_list + end \ No newline at end of file diff --git a/auth/initialize_database.rb b/auth/initialize_database.rb index 07a4af8..266281f 100644 --- a/auth/initialize_database.rb +++ b/auth/initialize_database.rb @@ -5,15 +5,25 @@ require 'sqlite3' def initialize_database puts 'Checking if database needs initializing.' - directory_path = './database' + database_path = DATA_LOCATION + DATABASE_SUBPATH + file_path = DATA_LOCATION + FILE_STORAGE_LOCATION + puts database_path - unless File.directory?(directory_path) - # If not, create the directory - Dir.mkdir(directory_path) - puts "Directory '#{directory_path}' created successfully." + unless File.directory?(DATA_LOCATION) + Dir.mkdir(DATA_LOCATION) + + unless File.directory?(database_path) + Dir.mkdir(database_path) + puts "Directory '#{database_path}' created successfully." + end + + unless File.directory?(file_path) + Dir.mkdir(file_path) + puts "Directory '#{file_path}' created successfully." + end end - - db = SQLite3::Database.new('./database/auth.db') + + db = SQLite3::Database.new( DATA_LOCATION + DATABASE_SUBPATH + DATABASE_NAME )#'./database/auth.db') puts 'Creating tables if necessary.' db.execute('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, username TEXT, hashed_password TEXT, is_admin INTEGER)') diff --git a/auth/post.rb b/auth/post.rb index 66ad471..55edadc 100644 --- a/auth/post.rb +++ b/auth/post.rb @@ -1,4 +1,5 @@ require 'net/http' +require 'net/http/post/multipart' require 'uri' require 'json' @@ -41,19 +42,55 @@ puts 'Reauthentication token stored.' response_data = JSON.parse(response.body) reauthentication_token = response_data['token'] -url = URI.parse('http://localhost:4567/auth/reauthenticate') -request = Net::HTTP::Post.new(url.path) +#while true + url = URI.parse('http://localhost:4567/auth/reauthenticate') + request = Net::HTTP::Post.new(url.path) -request['Authorization'] = "Bearer #{reauthentication_token}" + request['Authorization'] = "Bearer #{reauthentication_token}" -response = http.request(request) + response = http.request(request) + + unless response.code == '200' + puts "Response Code: #{response.code}. Aborting." + puts "Response Body: #{response.body}" + puts "Aborting." + exit + end + + #puts response.body + + response_data = JSON.parse(response.body) + authentication_token = response_data['jwt'] + + #end + + ############# Do Files Test + #sleep(2) + +# Read the file contents +file_content = File.read('./example.txt') + +# Create a URI object for the API endpoint +uri = URI.parse('http://localhost:4567/upload') + +# Create a Net::HTTP object +http = Net::HTTP.new(uri.host, uri.port) + +request = Net::HTTP::Post::Multipart.new( + uri.path, + 'file' => UploadIO.new(StringIO.new(file_content), 'application/octet-stream', 'example.txt') +) + +request['Authorization'] = "Bearer #{authentication_token}" + +# Send the request +puts "Sending file of size #{(File.size('./example.txt') / 2**20).round(2)} MB" +response = http.request(request) + +#puts response.code unless response.code == '200' - puts "Response Code: #{response.code}. Aborting." - puts "Response Body: #{response.body}" - puts "Aborting." - exit -end - - -puts response.body + puts response.code +else + puts response.body +end \ No newline at end of file