mirror of https://github.com/docusealco/docuseal
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
3.7 KiB
107 lines
3.7 KiB
# frozen_string_literal: true
|
|
|
|
require 'jwt'
|
|
|
|
describe 'Embed builder' do
|
|
let(:account) { create(:account) }
|
|
let(:user) { create(:user, account:) }
|
|
let(:api_key) { user.access_token.token }
|
|
|
|
def token(claims = {})
|
|
JWT.encode({ user_email: user.email, exp: 5.minutes.from_now.to_i }.merge(claims), api_key, 'HS256')
|
|
end
|
|
|
|
describe 'GET /embed/builder' do
|
|
it 'signs the owner in and redirects to /new for a fresh template' do
|
|
get embed_builder_path, params: {
|
|
token: token(document_urls: ['https://example.com/doc.pdf'], name: 'Consent Form', external_id: 'ext-123')
|
|
}
|
|
|
|
expect(response).to have_http_status(:found)
|
|
expect(response.location).to include('/new')
|
|
expect(response.location).to include('external_id=ext-123')
|
|
expect(response.location).to include('Consent_Form.pdf')
|
|
end
|
|
|
|
it 'redirects to the editor for an existing owned template' do
|
|
template = create(:template, account:, external_id: 'ext-xyz')
|
|
|
|
get embed_builder_path, params: { token: token(template_id: template.id) }
|
|
|
|
expect(response).to redirect_to(edit_template_path(template))
|
|
end
|
|
|
|
it 'never opens a template the account does not own — falls back to create' do
|
|
other = create(:template, account: create(:account), external_id: 'foreign')
|
|
|
|
get embed_builder_path, params: { token: token(template_id: other.id) }
|
|
|
|
expect(response.location).to include('/new')
|
|
expect(response.location).not_to include("/templates/#{other.id}")
|
|
end
|
|
|
|
it 'rejects a token signed with the wrong key' do
|
|
bad = JWT.encode({ user_email: user.email, exp: 5.minutes.from_now.to_i }, 'not-the-key', 'HS256')
|
|
|
|
get embed_builder_path, params: { token: bad }
|
|
|
|
expect(response).to redirect_to(new_user_session_path)
|
|
end
|
|
|
|
it 'rejects an expired token' do
|
|
get embed_builder_path, params: { token: token(exp: 1.minute.ago.to_i) }
|
|
|
|
expect(response).to redirect_to(new_user_session_path)
|
|
end
|
|
|
|
it 'rejects a token with no exp claim' do
|
|
bare = JWT.encode({ user_email: user.email }, api_key, 'HS256')
|
|
|
|
get embed_builder_path, params: { token: bare }
|
|
|
|
expect(response).to redirect_to(new_user_session_path)
|
|
end
|
|
|
|
it 'rejects a token whose lifetime exceeds the cap' do
|
|
get embed_builder_path, params: { token: token(exp: 1.hour.from_now.to_i) }
|
|
|
|
expect(response).to redirect_to(new_user_session_path)
|
|
end
|
|
|
|
it 'rejects a token for an unknown owner' do
|
|
foreign = JWT.encode({ user_email: 'nobody@example.com', exp: 5.minutes.from_now.to_i }, api_key, 'HS256')
|
|
|
|
get embed_builder_path, params: { token: foreign }
|
|
|
|
expect(response).to redirect_to(new_user_session_path)
|
|
end
|
|
end
|
|
|
|
describe 'scope enforcement (EmbedScoped)' do
|
|
it 'confines the embed session to its own template' do
|
|
mine = create(:template, account:, external_id: 'mine')
|
|
theirs = create(:template, account:, external_id: 'theirs')
|
|
|
|
get embed_builder_path, params: { token: token(template_id: mine.id) }
|
|
expect(response).to redirect_to(edit_template_path(mine))
|
|
|
|
# Cookies persist across requests within a request spec, so the next
|
|
# call rides the embed session established above.
|
|
get edit_template_path(mine)
|
|
expect(response).to have_http_status(:ok)
|
|
|
|
get edit_template_path(theirs)
|
|
expect(response).to have_http_status(:forbidden)
|
|
end
|
|
|
|
it 'refuses template enumeration even with a valid embed session' do
|
|
mine = create(:template, account:, external_id: 'mine')
|
|
|
|
get embed_builder_path, params: { token: token(template_id: mine.id) }
|
|
get '/templates'
|
|
|
|
expect(response).to have_http_status(:forbidden)
|
|
end
|
|
end
|
|
end
|