Initial commit
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
require "swagger_helper"
|
||||
|
||||
RSpec.describe "api/v1/admin", type: :request do
|
||||
path "/api/v1/admin/dashboard" do
|
||||
get "admin dashboard (admin only)" do
|
||||
tags "Admin"
|
||||
produces "application/json"
|
||||
security [ bearer_auth: [] ]
|
||||
|
||||
response "200", "admin dashboard accessed" do
|
||||
let!(:admin_user) { User.create!(email: "admin@example.com", password: "123456", password_confirmation: "123456", role: :admin) }
|
||||
let(:Authorization) { "Bearer #{JsonWebToken.encode(user_id: admin_user.id)}" }
|
||||
|
||||
run_test! do |response|
|
||||
data = JSON.parse(response.body)
|
||||
expect(data["message"]).to include("Welcome to admin dashboard")
|
||||
expect(data["stats"]).to be_present
|
||||
expect(data["stats"]["total_users"]).to be_a(Integer)
|
||||
end
|
||||
end
|
||||
|
||||
response "403", "forbidden for non-admin users" do
|
||||
let!(:regular_user) { User.create!(email: "user@example.com", password: "123456", password_confirmation: "123456", role: :user) }
|
||||
let(:Authorization) { "Bearer #{JsonWebToken.encode(user_id: regular_user.id)}" }
|
||||
|
||||
run_test! do |response|
|
||||
data = JSON.parse(response.body)
|
||||
expect(data["error"]).to include("Forbidden")
|
||||
end
|
||||
end
|
||||
|
||||
response "401", "unauthorized without token" do
|
||||
let(:Authorization) { "" }
|
||||
|
||||
run_test! do |response|
|
||||
data = JSON.parse(response.body)
|
||||
expect(data["error"]).to include("unauthorized")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,37 @@
|
||||
require "swagger_helper"
|
||||
|
||||
RSpec.describe "api/v1/auth", type: :request do
|
||||
path "/api/v1/login" do
|
||||
post "logs in a user" do
|
||||
tags "Auth"
|
||||
consumes "application/json"
|
||||
produces "application/json"
|
||||
security []
|
||||
parameter name: :credentials, in: :body, schema: {
|
||||
type: :object,
|
||||
required: %w[email password],
|
||||
properties: {
|
||||
email: {
|
||||
type: :string,
|
||||
example: "bob@random.com"
|
||||
},
|
||||
password: {
|
||||
type: :string,
|
||||
example: "123456"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response "200", "logged in" do
|
||||
let!(:user) { User.create(email: "bob@random.com", password: "123456", password_confirmation: "123456") }
|
||||
let(:credentials) { { email: "bob@random.com", password: "123456" } }
|
||||
run_test!
|
||||
end
|
||||
|
||||
response "401", "invalid credentials" do
|
||||
let(:credentials) { { email: "notbob@example.com", password: "wrong" } }
|
||||
run_test!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,55 @@
|
||||
require "swagger_helper"
|
||||
|
||||
RSpec.describe "api/v1/logout", type: :request do
|
||||
path "/api/v1/logout" do
|
||||
post "logs out user and blacklists token" do
|
||||
tags "Auth"
|
||||
consumes "application/json"
|
||||
produces "application/json"
|
||||
security [ bearer_auth: [] ]
|
||||
|
||||
let!(:user) { User.create!(email: "test@example.com", password: "123456", password_confirmation: "123456") }
|
||||
|
||||
response "200", "successfully logged out" do
|
||||
let(:Authorization) do
|
||||
token = JsonWebToken.encode(user_id: user.id)
|
||||
"Bearer #{token}"
|
||||
end
|
||||
|
||||
run_test! do |response|
|
||||
data = JSON.parse(response.body)
|
||||
expect(data["message"]).to include("Successfully logged out")
|
||||
|
||||
# verify token was blacklisted by checking the response
|
||||
# (we can't decode the token variable here as it's scoped to the let block)
|
||||
end
|
||||
end
|
||||
|
||||
response "401", "unauthorized without token" do
|
||||
let(:Authorization) { "" }
|
||||
|
||||
run_test! do |response|
|
||||
data = JSON.parse(response.body)
|
||||
expect(data["error"]).to include("unauthorized")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "blacklisted token rejection" do
|
||||
it "rejects requests with blacklisted tokens" do
|
||||
user = User.create!(email: "test@example.com", password: "123456", password_confirmation: "123456")
|
||||
token = JsonWebToken.encode(user_id: user.id)
|
||||
|
||||
# first logout to blacklist the token
|
||||
post "/api/v1/logout", headers: { "Authorization" => "Bearer #{token}" }
|
||||
expect(response).to have_http_status(:ok)
|
||||
|
||||
# try to access protected endpoint with blacklisted token
|
||||
get "/api/v1/profile", headers: { "Authorization" => "Bearer #{token}" }
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
data = JSON.parse(response.body)
|
||||
expect(data["error"]).to include("Token has been revoked")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
require "swagger_helper"
|
||||
|
||||
RSpec.describe "api/v1/profile", type: :request do
|
||||
path "/api/v1/profile" do
|
||||
get "get current user info using jwt token" do
|
||||
tags "Profile"
|
||||
security [ bearer_auth: [] ]
|
||||
produces "application/json"
|
||||
|
||||
response "200", "profile fetched" do
|
||||
let!(:user) { User.create(email: "bob@random.com", password: "123456", password_confirmation: "123456") }
|
||||
let(:Authorization) { "Bearer #{JsonWebToken.encode(user_id: user.id)}" }
|
||||
|
||||
run_test!
|
||||
end
|
||||
|
||||
response "401", "unauthorized access" do
|
||||
let(:Authorization) { "" }
|
||||
run_test!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,29 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe "Rack::Attack throttling", type: :request do
|
||||
describe "POST /api/v1/login" do
|
||||
let!(:user) do
|
||||
User.create(email: "bob@random.com", password: "123456", password_confirmation: "123456")
|
||||
end
|
||||
|
||||
it "throttles after 3 login attempts" do
|
||||
3.times do
|
||||
post "/api/v1/login", params: {
|
||||
email: "bob@random.com",
|
||||
password: "wrongpassword"
|
||||
}.to_json, headers: { "CONTENT_TYPE" => "application/json" }
|
||||
|
||||
expect(response.status).to_not eq(429)
|
||||
end
|
||||
|
||||
# this one is going to be blocked. too much attempt
|
||||
post "/api/v1/login", params: {
|
||||
email: "bob@random.com",
|
||||
password: "wrongpassword"
|
||||
}.to_json, headers: { "CONTENT_TYPE" => "application/json" }
|
||||
|
||||
expect(response.status).to eq(429)
|
||||
expect(response.body).to include("chill out")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,55 @@
|
||||
require "swagger_helper"
|
||||
|
||||
RSpec.describe "api/v1/refresh", type: :request do
|
||||
path "/api/v1/refresh" do
|
||||
post "refreshes access token using refresh token" do
|
||||
tags "Auth"
|
||||
consumes "application/json"
|
||||
produces "application/json"
|
||||
security []
|
||||
|
||||
parameter name: :refresh_request, in: :body, schema: {
|
||||
type: :object,
|
||||
required: %w[refresh_token],
|
||||
properties: {
|
||||
refresh_token: { type: :string, example: "your_refresh_token_here" }
|
||||
}
|
||||
}
|
||||
|
||||
let(:user) { User.create!(email: "test@example.com", password: "123456", password_confirmation: "123456") }
|
||||
let(:refresh_token_record) { user.refresh_tokens.create! }
|
||||
|
||||
response "200", "new access token issued" do
|
||||
let(:refresh_request) { { refresh_token: refresh_token_record.token } }
|
||||
|
||||
run_test! do |response|
|
||||
data = JSON.parse(response.body)
|
||||
expect(data["access_token"]).to be_present
|
||||
expect(data["user"]["email"]).to eq("test@example.com")
|
||||
end
|
||||
end
|
||||
|
||||
response "401", "invalid or expired refresh token" do
|
||||
let(:refresh_request) { { refresh_token: "invalid_token" } }
|
||||
|
||||
run_test! do |response|
|
||||
data = JSON.parse(response.body)
|
||||
expect(data["error"]).to include("Invalid or expired refresh token")
|
||||
end
|
||||
end
|
||||
|
||||
response "401", "revoked refresh token" do
|
||||
before do
|
||||
refresh_token_record.revoke!
|
||||
end
|
||||
|
||||
let(:refresh_request) { { refresh_token: refresh_token_record.token } }
|
||||
|
||||
run_test! do |response|
|
||||
data = JSON.parse(response.body)
|
||||
expect(data["error"]).to include("Invalid or expired refresh token")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,51 @@
|
||||
require "swagger_helper"
|
||||
|
||||
RSpec.describe "api/v1/signup", type: :request do
|
||||
path "/api/v1/signup" do
|
||||
post "registers a new user and returns a jwt" do
|
||||
tags "Auth"
|
||||
consumes "application/json"
|
||||
produces "application/json"
|
||||
security []
|
||||
|
||||
parameter name: :user, in: :body, schema: {
|
||||
type: :object,
|
||||
required: %w[email password password_confirmation],
|
||||
properties: {
|
||||
email: { type: :string, example: "newbob@example.com" },
|
||||
password: { type: :string, example: "123456" },
|
||||
password_confirmation: { type: :string, example: "123456" }
|
||||
}
|
||||
}
|
||||
|
||||
response "201", "user created and token returned" do
|
||||
let(:user) do
|
||||
{
|
||||
email: "newbob@example.com",
|
||||
password: "123456",
|
||||
password_confirmation: "123456"
|
||||
}
|
||||
end
|
||||
run_test!
|
||||
end
|
||||
|
||||
response "422", "validation failed invalid email + password" do
|
||||
let(:user) do
|
||||
{
|
||||
email: "",
|
||||
password: "123456",
|
||||
password_confirmation: "000000"
|
||||
}
|
||||
end
|
||||
|
||||
run_test! do |response|
|
||||
data = JSON.parse(response.body)
|
||||
expect(data["errors"]).to include(
|
||||
"Email can't be blank",
|
||||
"Password confirmation doesn't match Password"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user