Module: Tina4::Auth

Defined in:
lib/tina4/auth.rb

Constant Summary collapse

KEYS_DIR =
".keys"

Class Method Summary collapse

Class Method Details

.auth_handler(&block) ⇒ Object



53
54
55
56
57
58
59
# File 'lib/tina4/auth.rb', line 53

def auth_handler(&block)
  if block_given?
    @custom_handler = block
  else
    @custom_handler || method(:default_auth_handler)
  end
end

.bearer_authObject



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/tina4/auth.rb', line 61

def bearer_auth
  lambda do |env|
    auth_header = env["HTTP_AUTHORIZATION"] || ""
    return false unless auth_header =~ /\ABearer\s+(.+)\z/i

    token = Regexp.last_match(1)

    # API_KEY bypass — matches tina4_python behavior
    api_key = ENV["API_KEY"]
    if api_key && !api_key.empty? && token == api_key
      env["tina4.auth"] = { "api_key" => true }
      return true
    end

    result = validate_token(token)
    if result[:valid]
      env["tina4.auth"] = result[:payload]
      true
    else
      false
    end
  end
end

.default_secure_authObject

Default auth handler for secured routes (POST/PUT/PATCH/DELETE) Used automatically unless auth: false is passed



87
88
89
# File 'lib/tina4/auth.rb', line 87

def default_secure_auth
  @default_secure_auth ||= bearer_auth
end

.generate_token(payload, expires_in: 3600) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
# File 'lib/tina4/auth.rb', line 18

def generate_token(payload, expires_in: 3600)
  ensure_keys
  now = Time.now.to_i
  claims = payload.merge(
    "iat" => now,
    "exp" => now + expires_in,
    "nbf" => now
  )
  require "jwt"
  JWT.encode(claims, private_key, "RS256")
end

.hash_password(password) ⇒ Object



41
42
43
44
# File 'lib/tina4/auth.rb', line 41

def hash_password(password)
  require "bcrypt"
  BCrypt::Password.create(password)
end

.private_keyObject



91
92
93
# File 'lib/tina4/auth.rb', line 91

def private_key
  @private_key ||= OpenSSL::PKey::RSA.new(File.read(private_key_path))
end

.public_keyObject



95
96
97
# File 'lib/tina4/auth.rb', line 95

def public_key
  @public_key ||= OpenSSL::PKey::RSA.new(File.read(public_key_path))
end

.setup(root_dir = Dir.pwd) ⇒ Object



12
13
14
15
16
# File 'lib/tina4/auth.rb', line 12

def setup(root_dir = Dir.pwd)
  @keys_dir = File.join(root_dir, KEYS_DIR)
  FileUtils.mkdir_p(@keys_dir)
  ensure_keys
end

.validate_token(token) ⇒ Object



30
31
32
33
34
35
36
37
38
39
# File 'lib/tina4/auth.rb', line 30

def validate_token(token)
  ensure_keys
  require "jwt"
  decoded = JWT.decode(token, public_key, true, algorithm: "RS256")
  { valid: true, payload: decoded[0] }
rescue JWT::ExpiredSignature
  { valid: false, error: "Token expired" }
rescue JWT::DecodeError => e
  { valid: false, error: e.message }
end

.verify_password(password, hash) ⇒ Object



46
47
48
49
50
51
# File 'lib/tina4/auth.rb', line 46

def verify_password(password, hash)
  require "bcrypt"
  BCrypt::Password.new(hash) == password
rescue BCrypt::Errors::InvalidHash
  false
end