mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 02:11:08 -06:00
4c9ca24ccf
API keys are now only visible when first created. After that, only the first four characters are stored in the database for identification, along with an sha256 hash of the full key. This makes key usage easier to audit, and ensures attackers would not have access to the live site in the event of a database leak. This makes the merge lower risk, because we have some time to revert if needed. Once the change is confirmed to be working, we will add a second commit to drop the `key` column.
83 lines
2.3 KiB
Ruby
83 lines
2.3 KiB
Ruby
# encoding: utf-8
|
|
# frozen_string_literal: true
|
|
|
|
require 'rails_helper'
|
|
|
|
describe ApiKey do
|
|
fab!(:user) { Fabricate(:user) }
|
|
|
|
it { is_expected.to belong_to :user }
|
|
it { is_expected.to belong_to :created_by }
|
|
|
|
it 'generates a key when saving' do
|
|
api_key = ApiKey.new
|
|
api_key.save!
|
|
initial_key = api_key.key
|
|
expect(initial_key.length).to eq(64)
|
|
|
|
# Does not overwrite key when saving again
|
|
api_key.description = "My description here"
|
|
api_key.save!
|
|
expect(api_key.reload.key).to eq(initial_key)
|
|
end
|
|
|
|
it 'does not have the key when loading later from the database' do
|
|
api_key = ApiKey.create!
|
|
expect(api_key.key_available?).to eq(true)
|
|
expect(api_key.key.length).to eq(64)
|
|
|
|
api_key = ApiKey.find(api_key.id)
|
|
expect(api_key.key_available?).to eq(false)
|
|
expect { api_key.key }.to raise_error(ApiKey::KeyAccessError)
|
|
end
|
|
|
|
it "can lookup keys based on their hash" do
|
|
key = ApiKey.create!.key
|
|
expect(ApiKey.with_key(key).length).to eq(1)
|
|
end
|
|
|
|
it "can calculate the epoch correctly" do
|
|
expect(ApiKey.last_used_epoch.to_datetime).to be_a(DateTime)
|
|
|
|
SiteSetting.api_key_last_used_epoch = ""
|
|
expect(ApiKey.last_used_epoch).to eq(nil)
|
|
end
|
|
|
|
it "can automatically revoke keys" do
|
|
now = Time.now
|
|
|
|
SiteSetting.api_key_last_used_epoch = now - 2.years
|
|
SiteSetting.revoke_api_keys_days = 180 # 6 months
|
|
|
|
freeze_time now - 1.year
|
|
never_used = Fabricate(:api_key)
|
|
used_previously = Fabricate(:api_key)
|
|
used_previously.update(last_used_at: Time.zone.now)
|
|
used_recently = Fabricate(:api_key)
|
|
|
|
freeze_time now - 3.months
|
|
used_recently.update(last_used_at: Time.zone.now)
|
|
|
|
freeze_time now
|
|
ApiKey.revoke_unused_keys!
|
|
|
|
[never_used, used_previously, used_recently].each(&:reload)
|
|
expect(never_used.revoked_at).to_not eq(nil)
|
|
expect(used_previously.revoked_at).to_not eq(nil)
|
|
expect(used_recently.revoked_at).to eq(nil)
|
|
|
|
# Restore them
|
|
[never_used, used_previously, used_recently].each { |a| a.update(revoked_at: nil) }
|
|
|
|
# Move the epoch to 1 month ago
|
|
SiteSetting.api_key_last_used_epoch = now - 1.month
|
|
ApiKey.revoke_unused_keys!
|
|
|
|
[never_used, used_previously, used_recently].each(&:reload)
|
|
expect(never_used.revoked_at).to eq(nil)
|
|
expect(used_previously.revoked_at).to eq(nil)
|
|
expect(used_recently.revoked_at).to eq(nil)
|
|
end
|
|
|
|
end
|