Add Inkbunny credentials management functionality
- Introduced methods for managing Inkbunny cookies in the GlobalStatesController, including `ib_cookies`, `edit_ib_cookies`, and `update_ib_cookies`. - Added a new policy for managing Inkbunny cookies, restricting access to admin users. - Created views for displaying and editing Inkbunny credentials, enhancing user interaction. - Updated routes to include paths for Inkbunny cookies management. - Enhanced tests for the new functionality in the GlobalStatesController spec, ensuring proper handling of credentials.
This commit is contained in:
@@ -8,6 +8,8 @@ class GlobalStatesController < ApplicationController
|
||||
furaffinity-cookie-oaid
|
||||
].freeze
|
||||
|
||||
IB_COOKIE_KEYS = %w[inkbunny-username inkbunny-password inkbunny-sid].freeze
|
||||
|
||||
def index
|
||||
authorize GlobalState
|
||||
@global_states = policy_scope(GlobalState).order(:key)
|
||||
@@ -94,6 +96,56 @@ class GlobalStatesController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
def ib_cookies
|
||||
authorize GlobalState
|
||||
@ib_cookies =
|
||||
IB_COOKIE_KEYS.map do |key|
|
||||
GlobalState.find_by(key: key) ||
|
||||
GlobalState.new(key: key, value_type: :string)
|
||||
end
|
||||
end
|
||||
|
||||
def edit_ib_cookies
|
||||
authorize GlobalState
|
||||
@ib_cookies =
|
||||
IB_COOKIE_KEYS
|
||||
.reject { |key| key == "inkbunny-sid" }
|
||||
.map do |key|
|
||||
GlobalState.find_by(key: key) ||
|
||||
GlobalState.new(key: key, value_type: :string)
|
||||
end
|
||||
@ib_sid = GlobalState.find_by(key: "inkbunny-sid")
|
||||
end
|
||||
|
||||
def update_ib_cookies
|
||||
authorize GlobalState
|
||||
|
||||
begin
|
||||
ActiveRecord::Base.transaction do
|
||||
ib_cookies_params.each do |key, value|
|
||||
state = GlobalState.find_or_initialize_by(key: key)
|
||||
state.value = value
|
||||
state.value_type = :string
|
||||
state.save!
|
||||
end
|
||||
end
|
||||
|
||||
redirect_to ib_cookies_global_states_path,
|
||||
notice: "Inkbunny credentials were successfully updated."
|
||||
rescue ActiveRecord::RecordInvalid => e
|
||||
@ib_cookies =
|
||||
IB_COOKIE_KEYS
|
||||
.reject { |key| key == "inkbunny-sid" }
|
||||
.map do |key|
|
||||
GlobalState.find_by(key: key) ||
|
||||
GlobalState.new(key: key, value_type: :string)
|
||||
end
|
||||
@ib_sid = GlobalState.find_by(key: "inkbunny-sid")
|
||||
flash.now[:alert] = "Error updating Inkbunny credentials: #{e.message}"
|
||||
render :edit_ib_cookies, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_global_state
|
||||
@@ -107,4 +159,10 @@ class GlobalStatesController < ApplicationController
|
||||
def fa_cookies_params
|
||||
params.require(:fa_cookies).permit(*FA_COOKIE_KEYS)
|
||||
end
|
||||
|
||||
def ib_cookies_params
|
||||
params.require(:ib_cookies).permit(
|
||||
*IB_COOKIE_KEYS.reject { |key| key == "inkbunny-sid" },
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,14 +19,6 @@ class GlobalStatePolicy < ApplicationPolicy
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def new?
|
||||
create?
|
||||
end
|
||||
|
||||
def edit?
|
||||
update?
|
||||
end
|
||||
|
||||
def fa_cookies?
|
||||
user.admin?
|
||||
end
|
||||
@@ -39,9 +31,21 @@ class GlobalStatePolicy < ApplicationPolicy
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def ib_cookies?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def edit_ib_cookies?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
def update_ib_cookies?
|
||||
user.admin?
|
||||
end
|
||||
|
||||
class Scope < Scope
|
||||
def resolve
|
||||
user.admin? ? scope.all : scope.none
|
||||
scope.all
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
73
app/views/global_states/edit_ib_cookies.html.erb
Normal file
73
app/views/global_states/edit_ib_cookies.html.erb
Normal file
@@ -0,0 +1,73 @@
|
||||
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<div class="sm:flex sm:items-center">
|
||||
<div class="sm:flex-auto">
|
||||
<h1 class="text-2xl font-semibold text-slate-900">
|
||||
Edit Inkbunny Credentials
|
||||
</h1>
|
||||
<p class="mt-2 text-sm text-slate-700">
|
||||
Update the credentials used for Inkbunny authentication.
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
|
||||
<%= link_to "Back to Credentials",
|
||||
ib_cookies_global_states_path,
|
||||
class:
|
||||
"bg-slate-500 hover:bg-slate-700 text-white font-bold py-2 px-4 rounded" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 overflow-hidden bg-white shadow sm:rounded-lg">
|
||||
<div class="p-3 sm:p-4">
|
||||
<%= form_tag ib_cookies_global_states_path, method: :patch do %>
|
||||
<table class="min-w-full divide-y divide-slate-300">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="pb-2 text-left text-sm font-semibold text-slate-900">
|
||||
Field
|
||||
</th>
|
||||
<th class="pb-2 text-left text-sm font-semibold text-slate-900">
|
||||
Value
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-200">
|
||||
<% @ib_cookies.each do |cookie| %>
|
||||
<tr>
|
||||
<td class="py-2 pr-4 text-sm font-medium text-slate-900">
|
||||
<%= cookie.key.sub("inkbunny-", "").titleize %>
|
||||
</td>
|
||||
<td class="py-2 pr-4">
|
||||
<%= text_field_tag "ib_cookies[#{cookie.key}]",
|
||||
cookie.value,
|
||||
type: cookie.key == "inkbunny-password" ? "password" : "text",
|
||||
class:
|
||||
"block w-full rounded-md border-slate-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm" %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% if @ib_sid %>
|
||||
<tr>
|
||||
<td class="py-2 pr-4 text-sm font-medium text-slate-900">
|
||||
Session ID
|
||||
</td>
|
||||
<td class="py-2 pr-4 text-sm text-slate-500">
|
||||
<%= @ib_sid.value.present? ? @ib_sid.value : "(not set)" %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="mt-4 flex justify-end space-x-3">
|
||||
<%= link_to "Cancel",
|
||||
ib_cookies_global_states_path,
|
||||
class:
|
||||
"rounded-md border border-slate-300 bg-white py-2 px-4 text-sm font-medium text-slate-700 shadow-sm hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2" %>
|
||||
<%= submit_tag "Save",
|
||||
class:
|
||||
"inline-flex justify-center rounded-md border border-transparent bg-sky-600 py-2 px-4 text-sm font-medium text-white shadow-sm hover:bg-sky-700 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
55
app/views/global_states/ib_cookies.html.erb
Normal file
55
app/views/global_states/ib_cookies.html.erb
Normal file
@@ -0,0 +1,55 @@
|
||||
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
|
||||
<div class="sm:flex sm:items-center">
|
||||
<div class="sm:flex-auto">
|
||||
<h1 class="text-2xl font-semibold text-slate-900">
|
||||
Inkbunny Credentials
|
||||
</h1>
|
||||
<p class="mt-2 text-sm text-slate-700">
|
||||
Manage credentials for Inkbunny authentication.
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-4 space-x-4 sm:ml-16 sm:mt-0 sm:flex-none">
|
||||
<%= link_to "Back to Global States",
|
||||
global_states_path,
|
||||
class:
|
||||
"bg-slate-500 hover:bg-slate-700 text-white font-bold py-2 px-4 rounded mr-3" %>
|
||||
<%= link_to "Edit Credentials",
|
||||
ib_cookies_edit_global_states_path,
|
||||
class:
|
||||
"bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 overflow-hidden bg-white shadow sm:rounded-lg">
|
||||
<div class="p-3 sm:p-4">
|
||||
<table class="min-w-full divide-y divide-slate-300">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="pb-2 text-left text-sm font-semibold text-slate-900">
|
||||
Field
|
||||
</th>
|
||||
<th class="pb-2 text-left text-sm font-semibold text-slate-900">
|
||||
Value
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-slate-200">
|
||||
<% @ib_cookies.each do |cookie| %>
|
||||
<tr>
|
||||
<td class="py-2 pr-4 text-sm font-medium text-slate-900">
|
||||
<%= cookie.key.sub("inkbunny-", "").titleize %>
|
||||
</td>
|
||||
<td class="py-2 pr-4 text-sm text-slate-500">
|
||||
<% if cookie.key == "inkbunny-password" && cookie.value.present? %>
|
||||
••••••••
|
||||
<% else %>
|
||||
<%= cookie.value.present? ? cookie.value : "(not set)" %>
|
||||
<% end %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -11,6 +11,10 @@
|
||||
fa_cookies_global_states_path,
|
||||
class:
|
||||
"bg-slate-500 hover:bg-slate-700 text-white font-bold py-2 px-4 rounded" %>
|
||||
<%= link_to "Manage IB Cookies",
|
||||
ib_cookies_global_states_path,
|
||||
class:
|
||||
"bg-slate-500 hover:bg-slate-700 text-white font-bold py-2 px-4 rounded" %>
|
||||
<%= link_to "New Global State",
|
||||
new_global_state_path,
|
||||
class:
|
||||
|
||||
@@ -94,6 +94,10 @@ Rails.application.routes.draw do
|
||||
get "fa-cookies", to: "global_states#fa_cookies"
|
||||
get "fa-cookies/edit", to: "global_states#edit_fa_cookies"
|
||||
patch "fa-cookies", to: "global_states#update_fa_cookies"
|
||||
|
||||
get "ib-cookies", to: "global_states#ib_cookies"
|
||||
get "ib-cookies/edit", to: "global_states#edit_ib_cookies"
|
||||
patch "ib-cookies", to: "global_states#update_ib_cookies"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
613
db/schema.rb
generated
613
db/schema.rb
generated
File diff suppressed because it is too large
Load Diff
@@ -250,4 +250,149 @@ RSpec.describe GlobalStatesController, type: :controller do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "Inkbunny Credentials Management" do
|
||||
let(:ib_cookie_keys) do
|
||||
%w[inkbunny-username inkbunny-password inkbunny-sid]
|
||||
end
|
||||
|
||||
describe "GET #ib_cookies" do
|
||||
context "when no Inkbunny credentials exist" do
|
||||
before { GlobalState.delete_all }
|
||||
|
||||
it "returns a success response" do
|
||||
get :ib_cookies
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
it "assigns new GlobalState objects for all required credentials" do
|
||||
get :ib_cookies
|
||||
assigned_credentials = assigns(:ib_cookies)
|
||||
|
||||
expect(assigned_credentials.size).to eq(3)
|
||||
expect(assigned_credentials).to all(be_new_record)
|
||||
expect(assigned_credentials.map(&:key)).to match_array(ib_cookie_keys)
|
||||
expect(assigned_credentials.map(&:value_type).uniq).to eq(["string"])
|
||||
end
|
||||
end
|
||||
|
||||
context "when Inkbunny credentials exist" do
|
||||
it "assigns all Inkbunny credentials" do
|
||||
username = create(:global_state, :inkbunny_username)
|
||||
password = create(:global_state, :inkbunny_password)
|
||||
sid = create(:global_state, :inkbunny_sid)
|
||||
|
||||
get :ib_cookies
|
||||
expect(assigns(:ib_cookies)).to match_array([username, password, sid])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET #edit_ib_cookies" do
|
||||
context "when no Inkbunny credentials exist" do
|
||||
before { GlobalState.delete_all }
|
||||
|
||||
it "returns a success response" do
|
||||
get :edit_ib_cookies
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
it "assigns new GlobalState objects for editable credentials" do
|
||||
get :edit_ib_cookies
|
||||
assigned_credentials = assigns(:ib_cookies)
|
||||
|
||||
expect(assigned_credentials.size).to eq(2)
|
||||
expect(assigned_credentials).to all(be_new_record)
|
||||
expect(assigned_credentials.map(&:key)).to match_array(
|
||||
%w[inkbunny-username inkbunny-password],
|
||||
)
|
||||
expect(assigned_credentials.map(&:value_type).uniq).to eq(["string"])
|
||||
end
|
||||
|
||||
it "has a valid route" do
|
||||
expect(ib_cookies_edit_global_states_path).to eq(
|
||||
"/state/ib-cookies/edit",
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when Inkbunny credentials exist" do
|
||||
it "assigns editable credentials and session ID" do
|
||||
username = create(:global_state, :inkbunny_username)
|
||||
password = create(:global_state, :inkbunny_password)
|
||||
sid = create(:global_state, :inkbunny_sid)
|
||||
|
||||
get :edit_ib_cookies
|
||||
expect(assigns(:ib_cookies)).to match_array([username, password])
|
||||
expect(assigns(:ib_sid)).to eq(sid)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "PATCH #update_ib_cookies" do
|
||||
context "with valid parameters" do
|
||||
let(:valid_params) do
|
||||
{
|
||||
ib_cookies: {
|
||||
"inkbunny-username" => "newuser",
|
||||
"inkbunny-password" => "newpass",
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
it "creates or updates the credentials" do
|
||||
patch :update_ib_cookies, params: valid_params
|
||||
|
||||
username = GlobalState.find_by(key: "inkbunny-username")
|
||||
password = GlobalState.find_by(key: "inkbunny-password")
|
||||
|
||||
expect(username.value).to eq("newuser")
|
||||
expect(username.value_type).to eq("string")
|
||||
expect(password.value).to eq("newpass")
|
||||
expect(password.value_type).to eq("string")
|
||||
end
|
||||
|
||||
it "redirects to the credentials page" do
|
||||
patch :update_ib_cookies, params: valid_params
|
||||
expect(response).to redirect_to(ib_cookies_global_states_path)
|
||||
end
|
||||
|
||||
it "sets a success notice" do
|
||||
patch :update_ib_cookies, params: valid_params
|
||||
expect(flash[:notice]).to eq(
|
||||
"Inkbunny credentials were successfully updated.",
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "with invalid parameters" do
|
||||
let(:invalid_params) do
|
||||
{
|
||||
ib_cookies: {
|
||||
"inkbunny-username" => "",
|
||||
"inkbunny-password" => "",
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
it "does not create new credentials" do
|
||||
expect {
|
||||
patch :update_ib_cookies, params: invalid_params
|
||||
}.not_to change(GlobalState, :count)
|
||||
end
|
||||
|
||||
it "renders the edit template" do
|
||||
patch :update_ib_cookies, params: invalid_params
|
||||
expect(response).to render_template(:edit_ib_cookies)
|
||||
end
|
||||
|
||||
it "sets an error alert" do
|
||||
patch :update_ib_cookies, params: invalid_params
|
||||
expect(flash.now[:alert]).to match(
|
||||
/Error updating Inkbunny credentials:/,
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,43 @@
|
||||
FactoryBot.define do
|
||||
factory :global_state do
|
||||
sequence(:key) { |n| "key_#{n}" }
|
||||
sequence(:key) { |n| "test_key_#{n}" }
|
||||
value { "test_value" }
|
||||
value_type { :string }
|
||||
|
||||
trait :inkbunny_username do
|
||||
key { "inkbunny-username" }
|
||||
value { "testuser" }
|
||||
value_type { :string }
|
||||
end
|
||||
|
||||
trait :inkbunny_password do
|
||||
key { "inkbunny-password" }
|
||||
value { "testpass" }
|
||||
value_type { :string }
|
||||
end
|
||||
|
||||
trait :inkbunny_sid do
|
||||
key { "inkbunny-sid" }
|
||||
value { "testsid" }
|
||||
value_type { :string }
|
||||
end
|
||||
|
||||
trait :counter do
|
||||
sequence(:key) { |n| "counter_#{n}" }
|
||||
value { "123" }
|
||||
value_type { :counter }
|
||||
end
|
||||
|
||||
trait :duration do
|
||||
sequence(:key) { |n| "duration_#{n}" }
|
||||
value { "30s" }
|
||||
value_type { :duration }
|
||||
end
|
||||
|
||||
trait :password do
|
||||
sequence(:key) { |n| "password_#{n}" }
|
||||
value { "secret" }
|
||||
value_type { :password }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user