Add brakeman and some tests

This commit is contained in:
Eugene Burmakin 2025-04-04 22:16:52 +02:00
parent 67916c10c4
commit 41604d71a6
9 changed files with 166 additions and 19 deletions

View file

@ -45,6 +45,7 @@ gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby]
gem 'jwt'
group :development, :test do
gem 'brakeman', require: false
gem 'debug', platforms: %i[mri mingw x64_mingw]
gem 'dotenv-rails'
gem 'factory_bot_rails'

View file

@ -101,6 +101,8 @@ GEM
bigdecimal (3.1.9)
bootsnap (1.18.4)
msgpack (~> 1.2)
brakeman (7.0.2)
racc
builder (3.3.0)
byebug (11.1.3)
chartkick (5.1.3)
@ -476,6 +478,7 @@ DEPENDENCIES
aws-sdk-kms (~> 1.96.0)
aws-sdk-s3 (~> 1.177.0)
bootsnap
brakeman
chartkick
data_migrate
database_consistency

View file

@ -31,6 +31,12 @@ class ApplicationController < ActionController::Base
redirect_to root_path, notice: 'Your account is not active.', status: :see_other
end
def authenticate_non_self_hosted!
return unless DawarichSettings.self_hosted?
redirect_to root_path, notice: 'You are not authorized to perform this action.', status: :see_other
end
private
def set_self_hosted_status

View file

@ -2,6 +2,7 @@
class Settings::SubscriptionsController < ApplicationController
before_action :authenticate_user!
before_action :authenticate_non_self_hosted!
def index; end
@ -16,13 +17,12 @@ class Settings::SubscriptionsController < ApplicationController
{ algorithm: 'HS256' }
).first.symbolize_keys
# Verify this is for the current user
unless decoded_token[:user_id] == current_user.id
redirect_to settings_subscriptions_path, alert: 'Invalid subscription update request.'
return
end
current_user.update!(status: decoded_token[:status])
current_user.update!(status: decoded_token[:status], active_until: decoded_token[:active_until])
redirect_to settings_subscriptions_path, notice: 'Your subscription has been updated successfully!'
rescue JWT::DecodeError

View file

@ -59,12 +59,11 @@ module Distanceable
return 0 if points.length < 2
total_meters = points.each_cons(2).sum do |point1, point2|
connection.select_value(<<-SQL.squish)
SELECT ST_Distance(
ST_GeomFromEWKT('#{point1.lonlat}')::geography,
ST_GeomFromEWKT('#{point2.lonlat}')::geography
)
SQL
connection.select_value(
'SELECT ST_Distance(ST_GeomFromEWKT($1)::geography, ST_GeomFromEWKT($2)::geography)',
nil,
[point1.lonlat, point2.lonlat]
)
end
total_meters.to_f / DISTANCE_UNITS[unit.to_sym]

View file

@ -12,13 +12,17 @@ module Visits
end
def call
bounding_box = "ST_MakeEnvelope(#{sw_lng}, #{sw_lat}, #{ne_lng}, #{ne_lat}, 4326)"
Visit
.includes(:place)
.where(user:)
.joins(:place)
.where("ST_Contains(#{bounding_box}, ST_SetSRID(places.lonlat::geometry, 4326))")
.where(
'ST_Contains(ST_MakeEnvelope(?, ?, ?, ?, 4326), ST_SetSRID(places.lonlat::geometry, 4326))',
sw_lng,
sw_lat,
ne_lng,
ne_lat
)
.order(started_at: :desc)
end

View file

@ -7,7 +7,7 @@ RSpec.describe BulkVisitsSuggestingJob, type: :job do
let(:start_at) { 1.day.ago.beginning_of_day }
let(:end_at) { 1.day.ago.end_of_day }
let(:user) { create(:user) }
let(:inactive_user) { create(:user, status: :inactive) }
let(:inactive_user) { create(:user, :inactive) }
let(:user_with_points) { create(:user) }
let(:time_chunks) { [[start_at, end_at]] }

View file

@ -31,7 +31,7 @@ RSpec.describe User, type: :model do
describe '#activate' do
context 'when self-hosted' do
let!(:user) { create(:user, status: :inactive, active_until: 1.day.ago) }
let!(:user) { create(:user, :inactive) }
before do
allow(DawarichSettings).to receive(:self_hosted?).and_return(true)
@ -49,7 +49,7 @@ RSpec.describe User, type: :model do
end
it 'does not activate user' do
user = create(:user, status: :inactive, active_until: 1.day.ago)
user = create(:user, :inactive)
expect(user.active?).to be_falsey
expect(user.active_until).to be_within(1.minute).of(1.day.ago)
@ -194,7 +194,7 @@ RSpec.describe User, type: :model do
end
context 'when user is inactive' do
let(:user) { create(:user, status: :inactive, active_until: 1.day.ago) }
let(:user) { create(:user, :inactive) }
it 'returns false' do
expect(user.can_subscribe?).to be_falsey
@ -216,7 +216,7 @@ RSpec.describe User, type: :model do
end
context 'when user is inactive' do
let(:user) { create(:user, status: :inactive, active_until: 1.day.ago) }
let(:user) { create(:user, :inactive) }
it 'returns true' do
expect(user.can_subscribe?).to be_truthy

View file

@ -1,7 +1,141 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe "Settings::Subscriptions", type: :request do
describe "GET /index" do
pending "add some examples (or delete) #{__FILE__}"
RSpec.describe 'Settings::Subscriptions', type: :request do
let(:user) { create(:user, :inactive) }
let(:jwt_secret) { ENV['JWT_SECRET_KEY'] }
before do
stub_const('ENV', ENV.to_h.merge('JWT_SECRET_KEY' => 'test_secret'))
stub_request(:any, 'https://api.github.com/repos/Freika/dawarich/tags')
.to_return(status: 200, body: '[{"name": "1.0.0"}]', headers: {})
end
context 'when Dawarich is not self-hosted' do
before do
allow(DawarichSettings).to receive(:self_hosted?).and_return(false)
end
describe 'GET /settings/subscriptions' do
context 'when user is not authenticated' do
it 'redirects to login page' do
get settings_subscriptions_path
expect(response).to redirect_to(new_user_session_path)
end
end
context 'when user is authenticated' do
before { sign_in user }
it 'returns successful response' do
get settings_subscriptions_path
expect(response).to be_successful
end
end
end
describe 'GET /settings/subscriptions/callback' do
context 'when user is not authenticated' do
it 'redirects to login page' do
get subscription_callback_settings_subscriptions_path(token: 'invalid')
expect(response).to redirect_to(new_user_session_path)
end
end
context 'when user is authenticated' do
before { sign_in user }
context 'with valid token' do
let(:token) do
JWT.encode(
{ user_id: user.id, status: 'active', active_until: 1.year.from_now },
jwt_secret,
'HS256'
)
end
it 'updates user status and redirects with success message' do
get subscription_callback_settings_subscriptions_path(token: token)
expect(user.reload.status).to eq('active')
expect(user.active_until).to be_within(1.day).of(1.year.from_now)
expect(response).to redirect_to(settings_subscriptions_path)
expect(flash[:notice]).to eq('Your subscription has been updated successfully!')
end
end
context 'with token for different user' do
let(:other_user) { create(:user) }
let(:token) do
JWT.encode(
{ user_id: other_user.id, status: 'active' },
jwt_secret,
'HS256'
)
end
it 'does not update status and redirects with error' do
get subscription_callback_settings_subscriptions_path(token: token)
expect(user.reload.status).not_to eq('active')
expect(response).to redirect_to(settings_subscriptions_path)
expect(flash[:alert]).to eq('Invalid subscription update request.')
end
end
context 'with invalid token' do
it 'redirects with decode error message' do
get subscription_callback_settings_subscriptions_path(token: 'invalid')
expect(response).to redirect_to(settings_subscriptions_path)
expect(flash[:alert]).to eq('Failed to verify subscription update.')
end
end
context 'with malformed token data' do
let(:token) do
JWT.encode({ user_id: 'invalid', status: nil }, jwt_secret, 'HS256')
end
it 'redirects with invalid data message' do
get subscription_callback_settings_subscriptions_path(token: token)
expect(response).to redirect_to(settings_subscriptions_path)
expect(flash[:alert]).to eq('Invalid subscription update request.')
end
end
end
end
end
context 'when Dawarich is self-hosted' do
before do
allow(DawarichSettings).to receive(:self_hosted?).and_return(true)
sign_in user
end
describe 'GET /settings/subscriptions' do
context 'when user is not authenticated' do
it 'redirects to root path' do
get settings_subscriptions_path
expect(response).to redirect_to(root_path)
end
end
end
describe 'GET /settings/subscriptions/callback' do
context 'when user is not authenticated' do
it 'redirects to root path' do
get subscription_callback_settings_subscriptions_path(token: 'invalid')
expect(response).to redirect_to(root_path)
end
end
end
end
end