Skip to content

Commit 004a22c

Browse files
authored
Merge from docusealco/wip
2 parents 54454d1 + 69343b1 commit 004a22c

19 files changed

Lines changed: 1534 additions & 146 deletions

.github/workflows/ci.yml

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -111,48 +111,39 @@ jobs:
111111
rspec:
112112
name: RSpec
113113
runs-on: ubuntu-latest
114-
timeout-minutes: 10
114+
timeout-minutes: 15
115+
container:
116+
image: ruby:4.0.5-alpine
115117

116118
services:
117119
postgres:
118-
image: postgres:14
120+
image: postgres:18
119121
env:
120122
POSTGRES_USER: postgres
121123
POSTGRES_PASSWORD: postgres
122124
POSTGRES_DB: docuseal_test
123-
ports: ["5432:5432"]
124125
options: >-
125-
--health-cmd pg_isready
126+
--health-cmd "pg_isready -U postgres -d docuseal_test"
126127
--health-interval 10s
127128
--health-timeout 5s
128129
--health-retries 5
129130
130131
steps:
132+
- name: Install packages
133+
run: apk add --no-cache build-base git libpq-dev yaml-dev nodejs yarn tar zstd gzip wget unzip vips leptonica chromium
131134
- uses: actions/checkout@v4
132-
- name: Install Ruby
133-
uses: ruby/setup-ruby@v1
134-
with:
135-
ruby-version: 4.0.5
136-
- name: Set up Node
137-
uses: actions/setup-node@v1
138-
with:
139-
node-version: 20.19.0
140-
- name: Install Chrome
141-
uses: browser-actions/setup-chrome@latest
142-
with:
143-
chrome-version: 125
144135
- name: Cache node_modules
145136
uses: actions/cache@v4
146137
with:
147138
path: node_modules
148-
key: ${{ runner.os }}-node-${{ hashFiles('**/yarn.lock') }}
139+
key: ${{ runner.os }}-musl-node-${{ hashFiles('**/yarn.lock') }}
149140
- name: Cache gems
150141
uses: actions/cache@v4
151142
with:
152143
path: vendor/bundle
153-
key: ${{ runner.os }}-gem-${{ hashFiles('**/Gemfile.lock') }}
144+
key: ${{ runner.os }}-musl-gem-${{ hashFiles('**/Gemfile.lock') }}
154145
restore-keys: |
155-
${{ runner.os }}-gem-
146+
${{ runner.os }}-musl-gem-
156147
- name: Install dependencies
157148
env:
158149
RAILS_ENV: test
@@ -161,17 +152,20 @@ jobs:
161152
bundle config path vendor/bundle
162153
bundle install --jobs 4 --retry 4
163154
yarn install
164-
sudo apt-get update
165-
sudo apt-get install -y libvips liblept5
166-
wget -O pdfium-linux.tgz "https://github.com/bblanchon/pdfium-binaries/releases/latest/download/pdfium-linux-$(uname -m | sed 's/x86_64/x64/;s/aarch64/arm64/').tgz"
167-
sudo tar -xzf pdfium-linux.tgz --strip-components=1 -C /usr/lib lib/libpdfium.so
168-
rm -f pdfium-linux.tgz
155+
wget -O pdfium-linux.zip "https://github.com/docusealco/pdfium-binaries/releases/download/20260813/pdfium-musl-$(uname -m).zip"
156+
case "$(uname -m)" in
157+
x86_64) echo "c5c7dde243ecb66ab0819c8193515ef38ad53549fe260f3c2dfd93ea56eda2e7 pdfium-linux.zip" ;;
158+
aarch64) echo "64c4483449b1b4dccc696ad0c5c96e0b7f74dcc57b4f23c676b7a70671b0bbb5 pdfium-linux.zip" ;;
159+
esac | sha256sum -c -
160+
unzip -q pdfium-linux.zip -d /tmp/pdfium-linux
161+
cp /tmp/pdfium-linux/lib/libpdfium.so /usr/lib/libpdfium.so
162+
rm -rf pdfium-linux.zip /tmp/pdfium-linux
169163
- name: Run
170164
env:
171165
RAILS_ENV: test
172166
NODE_ENV: test
173167
COVERAGE: true
174-
DATABASE_URL: postgres://postgres:postgres@localhost:5432/docuseal_test
168+
DATABASE_URL: postgres://postgres:postgres@postgres:5432/docuseal_test
175169
run: |
176170
bundle exec rake db:create
177171
bundle exec rake db:migrate

Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ RUN apk --no-cache add wget unzip && \
99
wget https://raw.githubusercontent.com/impallari/DancingScript/master/OFL.txt && \
1010
wget https://raw.githubusercontent.com/notofonts/noto-fonts/refs/heads/main/LICENSE && \
1111
wget -O /model.onnx "https://github.com/docusealco/fields-detection/releases/download/2.0.0/model_704_int8.onnx" && \
12-
wget -O pdfium-linux.zip "https://github.com/docusealco/pdfium-binaries/releases/download/20260613/pdfium-musl-$(uname -m).zip" && \
12+
wget -O pdfium-linux.zip "https://github.com/docusealco/pdfium-binaries/releases/download/20260813/pdfium-musl-$(uname -m).zip" && \
1313
case "$(uname -m)" in \
14-
x86_64) echo "2c953ff72ee2dda07e7fc577e25841cc3d6464468a7c5adfaea574efcbc3b90b pdfium-linux.zip" ;; \
15-
aarch64) echo "23bbe287d2753fdb05741c7660647eb0ef0d2e4da2ce0722bfa9d9d455bd64e2 pdfium-linux.zip" ;; \
14+
x86_64) echo "c5c7dde243ecb66ab0819c8193515ef38ad53549fe260f3c2dfd93ea56eda2e7 pdfium-linux.zip" ;; \
15+
aarch64) echo "64c4483449b1b4dccc696ad0c5c96e0b7f74dcc57b4f23c676b7a70671b0bbb5 pdfium-linux.zip" ;; \
1616
esac | sha256sum -c - && \
1717
mkdir -p /pdfium-linux && \
1818
unzip -q pdfium-linux.zip -d /pdfium-linux

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ GEM
271271
rdoc (>= 4.0.0)
272272
reline (>= 0.4.2)
273273
jmespath (1.6.2)
274-
json (2.21.1)
274+
json (2.21.2)
275275
jwt (3.2.0)
276276
base64
277277
language_server-protocol (3.17.0.5)

app/controllers/templates_uploads_controller.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ class TemplatesUploadsController < ApplicationController
66
layout 'plain'
77

88
def show
9-
redirect_to root_path if params[:url].blank?
9+
url_uri = Addressable::URI.parse(params[:url].to_s)
10+
11+
redirect_to root_path if url_uri.normalized_scheme != 'https' || url_uri.host.blank?
1012
end
1113

1214
def create

app/controllers/verify_pdf_signature_controller.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ class VerifyPdfSignatureController < ApplicationController
44
skip_authorization_check
55

66
def create
7-
pdfs =
7+
trusted_certs = Accounts.load_trusted_certs(current_account)
8+
9+
signatures =
810
params[:files].map do |file|
9-
HexaPDF::Document.new(io: file.open)
11+
VerifyPdfSignature.call(file.open, trusted_certs)
1012
end
1113

12-
trusted_certs = Accounts.load_trusted_certs(current_account)
13-
1414
render turbo_stream: turbo_stream.replace('result', partial: 'result',
15-
locals: { pdfs:, files: params[:files], trusted_certs: })
16-
rescue HexaPDF::MalformedPDFError
15+
locals: { signatures:, files: params[:files] })
16+
rescue Pdfium::PdfiumError
1717
render turbo_stream: turbo_stream.replace('result', html: helpers.tag.div(I18n.t('invalid_pdf'), id: 'result'))
1818
end
1919
end

app/jobs/process_submitter_completion_job.rb

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,18 @@ def enqueue_completed_emails(submitter)
123123

124124
user = submission.created_by_user || template.author
125125

126+
copy_email_configs = AccountConfigs.find_or_initialize_for_key(submitter.account,
127+
AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY)
128+
129+
is_copy_email_enabled = documents_copy_email_enabled?(submitter, copy_email_configs)
130+
126131
if submitter.account.users.exists?(id: user.id) && submission.preferences['send_email'] != false &&
127132
(!template || template.preferences['completed_notification_email_enabled'] != false)
128133
user_submitter = submission.submitters.find { |s| s.email == user.email }
129134

130135
is_sent_to_user =
131136
if user.role != 'integration' &&
132-
(!user_submitter || user_submitter.preferences['send_email'] == false) &&
137+
(!user_submitter || user_submitter.preferences['send_email'] == false || !is_copy_email_enabled) &&
133138
user.user_configs.find_by(key: UserConfig::RECEIVE_COMPLETED_EMAIL)&.value != false
134139
SubmitterMailer.completed_email(submitter, user).deliver_later!
135140

@@ -139,11 +144,11 @@ def enqueue_completed_emails(submitter)
139144
enqueue_bcc_completed_emails(submitter, user, is_sent_to_user)
140145
end
141146

142-
maybe_enqueue_copy_emails(submitter)
147+
enqueue_copy_emails(submitter, copy_email_configs) if is_copy_email_enabled
143148
end
144149

145150
def enqueue_bcc_completed_emails(submitter, user, is_sent_to_user)
146-
bcc_addresses = build_bcc_addresses(submitter.submission)
151+
bcc_addresses = build_bcc_addresses(submitter.submission).uniq
147152

148153
raise TooManyBcc, submitter.account_id if Docuseal.multitenant? && bcc_addresses.size > BCC_LIMIT
149154

@@ -154,14 +159,13 @@ def enqueue_bcc_completed_emails(submitter, user, is_sent_to_user)
154159
end
155160
end
156161

157-
def maybe_enqueue_copy_emails(submitter)
158-
return if submitter.template&.preferences&.dig('documents_copy_email_enabled') == false
162+
def documents_copy_email_enabled?(submitter, configs)
163+
return false if submitter.template&.preferences&.dig('documents_copy_email_enabled') == false
159164

160-
configs = AccountConfigs.find_or_initialize_for_key(submitter.account,
161-
AccountConfig::SUBMITTER_DOCUMENTS_COPY_EMAIL_KEY)
162-
163-
return if configs.value['enabled'] == false
165+
configs.value['enabled'] != false
166+
end
164167

168+
def enqueue_copy_emails(submitter, configs)
165169
to = submitter.submission.submitters.reject { |e| e.preferences['send_email'] == false }
166170
.sort_by { |e| e.completed_at || Time.current }.select(&:email?).map(&:friendly_name)
167171

app/views/submissions_filters/_filter_modal.html.erb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
<% path_uri = Addressable::URI.parse(params[:path].to_s) %>
2+
<% path = url_for(**Rails.application.routes.recognize_path(path_uri.path, method: :get)) %>
13
<%= render 'shared/turbo_modal', title: local_assigns[:title] do %>
2-
<%= form_for '', url: params[:path], method: :get, data: { turbo_frame: :_top }, html: { autocomplete: :off } do |f| %>
4+
<%= form_for '', url: path, method: :get, data: { turbo_frame: :_top }, html: { autocomplete: :off } do |f| %>
35
<%= hidden_field_tag :q, params[:q] if params[:q].present? %>
46
<% local_assigns[:default_params].each do |key, value| %>
57
<%= hidden_field_tag(key, value) if value.present? %>
@@ -10,7 +12,7 @@
1012
</div>
1113
<% if params[:with_remove] %>
1214
<div class="text-center w-full mt-4">
13-
<%= link_to t('remove_filter'), "#{params[:path]}?#{request.query_parameters.slice('q').merge(local_assigns[:default_params]).to_query}", class: 'link', data: { turbo_frame: :_top } %>
15+
<%= link_to t('remove_filter'), "#{path}?#{request.query_parameters.slice('q').merge(local_assigns[:default_params]).to_query}", class: 'link', data: { turbo_frame: :_top } %>
1416
</div>
1517
<% end %>
1618
<% end %>

app/views/verify_pdf_signature/_result.html.erb

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<div id="result">
2-
<% files.zip(pdfs).each do |file, pdf| %>
2+
<% files.zip(signatures).each do |file, file_signatures| %>
33
<div class="mb-4 border border-base-300 rounded-md py-2 px-3">
4-
<% if pdf.signatures.to_a.size == 0 %>
4+
<% if file_signatures.size == 0 %>
55
<div class="text-sm">
66
<%= file.original_filename %>
77
</div>
@@ -11,54 +11,41 @@
1111
<% else %>
1212
<div class="flex items-center space-x-1 border-b border-dashed border-base-300 pb-2">
1313
<%= svg_icon('file_text', class: 'w-5 h-5 inline') %>
14-
<span><%= file.original_filename %> - <%= pluralize(pdf.signatures.to_a.size, 'Signature') %></span>
14+
<span><%= file.original_filename %> - <%= pluralize(file_signatures.size, 'Signature') %></span>
1515
</div>
16-
<% pdf.signatures.to_a.each do |signature| %>
16+
<% file_signatures.each do |signature| %>
1717
<div class="mt-3">
1818
<div class="space-y-1 font-medium pb-2 text-xl">
19-
<% signature.verify(trusted_certs:).messages.map(&:content).each do |message| %>
19+
<% signature.messages.each do |message| %>
2020
<p class="flex space-x-1 items-center">
21-
<% if message == 'Signature verification failed' %>
21+
<% if message.status == :error %>
2222
<%= svg_icon('x_circle', class: 'w-6 h-6 text-red-500') %>
23-
<% elsif message == 'Signature valid' %>
23+
<% elsif message.status == :success %>
2424
<%= svg_icon('circle_check', class: 'w-6 h-6 text-green-500') %>
25+
<% elsif message.status == :warning %>
26+
<%= svg_icon('alert_circle', class: 'w-6 h-6 text-yellow-500') %>
2527
<% end %>
2628
<span>
27-
<%= message %>
29+
<%= message.text %>
2830
</span>
2931
</p>
30-
<% if message == 'Signature valid' %>
31-
<p class="flex space-x-1 items-center">
32-
<% if trusted_certs.any? { |e| e.public_key.to_der == signature.signature_handler.signer_certificate.public_key.to_der } %>
33-
<%= svg_icon('circle_check', class: 'w-6 h-6 text-green-500') %>
34-
<span>
35-
<%= t('signed_with_trusted_certificate') %>
36-
</span>
37-
<% else %>
38-
<%= svg_icon('x_circle', class: 'w-6 h-6 text-red-500') %>
39-
<span>
40-
<%= t('signed_with_external_certificate') %>
41-
</span>
42-
<% end %>
43-
</p>
44-
<% end %>
4532
<% end %>
4633
</div>
4734
<div class="flex items-center space-x-1">
4835
<%= svg_icon('user', class: 'w-5 h-5 inline') %>
49-
<span><%= signature.signing_reason %></span>
36+
<span><%= signature.reason %></span>
5037
</div>
5138
<div class="flex items-center space-x-1">
5239
<%= svg_icon('calendar', class: 'w-5 h-5 inline') %>
5340
<span><%= l(signature.signing_time.in_time_zone(current_account.timezone), format: :long, locale: current_account.locale) %></span>
5441
</div>
5542
<div class="flex items-center space-x-1">
5643
<%= svg_icon('certificate', class: 'w-5 h-5 inline') %>
57-
<span><%= signature.signer_name.force_encoding('UTF-8') %></span>
44+
<span><%= signature.common_name %></span>
5845
</div>
5946
<div class="flex items-center space-x-1">
6047
<%= svg_icon('lock_access', class: 'w-5 h-5 inline') %>
61-
<span><%= signature.signature_type %></span>
48+
<span><%= signature.type %></span>
6249
</div>
6350
</div>
6451
<% end %>

config/application.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ module DocuSeal
1919
class Application < Rails::Application
2020
config.load_defaults 8.1
2121

22+
config.active_support.message_serializer = :json
23+
2224
config.autoload_lib(ignore: %w[assets tasks puma])
2325

2426
config.active_storage.routes_prefix = ''

0 commit comments

Comments
 (0)