diff --git a/app/controllers/api/submissions_controller.rb b/app/controllers/api/submissions_controller.rb index 2fc30c4c..ce8334fc 100644 --- a/app/controllers/api/submissions_controller.rb +++ b/app/controllers/api/submissions_controller.rb @@ -11,7 +11,7 @@ module Api user: current_user, source: :api, send_email: params[:send_email] != 'false', - emails: params[:emails]) + emails: params[:emails] || params[:email]) else Submissions.create_from_submitters(template:, user: current_user, diff --git a/app/models/access_token.rb b/app/models/access_token.rb new file mode 100644 index 00000000..5f8be162 --- /dev/null +++ b/app/models/access_token.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: access_tokens +# +# id :bigint not null, primary key +# sha256 :text not null +# token :text not null +# created_at :datetime not null +# updated_at :datetime not null +# user_id :bigint not null +# +# Indexes +# +# index_access_tokens_on_sha256 (sha256) UNIQUE +# index_access_tokens_on_user_id (user_id) +# +# Foreign Keys +# +# fk_rails_... (user_id => users.id) +# +class AccessToken < ApplicationRecord + TOKEN_LENGTH = 22 + + belongs_to :user + + before_validation :set_sha256, on: :create + + attribute :token, :string, default: -> { SecureRandom.base58(TOKEN_LENGTH) } + + encrypts :token + + private + + def set_sha256 + self.sha256 = Digest::SHA256.hexdigest(token) + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 8d5a098e..5213173c 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -45,6 +45,7 @@ class User < ApplicationRecord EMAIL_REGEXP = /[^@,\s]+@[^@,\s]+/ belongs_to :account + has_one :access_token, dependent: :destroy devise :database_authenticatable, :recoverable, :rememberable, :validatable, :trackable devise :registerable, :omniauthable, omniauth_providers: [:google_oauth2] if Docuseal.multitenant? @@ -54,6 +55,10 @@ class User < ApplicationRecord scope :active, -> { where(deleted_at: nil) } + def access_token + super || build_access_token.tap(&:save!) + end + def active_for_authentication? !deleted_at? end diff --git a/app/views/api_settings/index.html.erb b/app/views/api_settings/index.html.erb index 489f2b1e..459b2eb2 100644 --- a/app/views/api_settings/index.html.erb +++ b/app/views/api_settings/index.html.erb @@ -6,8 +6,8 @@
- - <%= render 'shared/clipboard_copy', icon: 'copy', text: jwt, class: 'base-button', icon_class: 'w-6 h-6 text-white', copy_title: 'Copy', copied_title: 'Copied' %> + + <%= render 'shared/clipboard_copy', icon: 'copy', text: current_user.access_token.token, class: 'base-button', icon_class: 'w-6 h-6 text-white', copy_title: 'Copy', copied_title: 'Copied' %>
@@ -26,7 +26,7 @@
<% text = capture do %>curl --location '<%= api_submissions_url %>' \ - --header 'X-Auth-Token: <%= jwt %>' \ + --header 'X-Auth-Token: <%= current_user.access_token.token %>' \ --data-raw '{ "template_id": <%= current_account.templates.last&.id || 1 %>, "emails": "<%= current_user.email.sub('@', '+test@') %>, <%= current_user.email.sub('@', '+test2@') %>" @@ -52,7 +52,7 @@
<% text = capture do %>curl --location '<%= api_submissions_url %>' \ - --header 'X-Auth-Token: <%= jwt %>' \ + --header 'X-Auth-Token: <%= current_user.access_token.token %>' \ --data-raw '{ "template_id": <%= current_account.templates.last&.id || 1 %>, "submission": [ diff --git a/db/migrate/20230806140534_create_access_tokens.rb b/db/migrate/20230806140534_create_access_tokens.rb new file mode 100644 index 00000000..a36fdda1 --- /dev/null +++ b/db/migrate/20230806140534_create_access_tokens.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class CreateAccessTokens < ActiveRecord::Migration[7.0] + def change + create_table :access_tokens do |t| + t.references :user, null: false, foreign_key: true, index: true + t.text :token, null: false + t.text :sha256, null: false, index: { unique: true } + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 304efa17..a26aafb2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,10 +10,20 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_08_05_124454) do +ActiveRecord::Schema[7.0].define(version: 2023_08_06_140534) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" + create_table "access_tokens", force: :cascade do |t| + t.bigint "user_id", null: false + t.text "token", null: false + t.text "sha256", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["sha256"], name: "index_access_tokens_on_sha256", unique: true + t.index ["user_id"], name: "index_access_tokens_on_user_id" + end + create_table "accounts", force: :cascade do |t| t.string "name", null: false t.string "timezone", null: false @@ -148,6 +158,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_08_05_124454) do t.index ["uuid"], name: "index_users_on_uuid", unique: true end + add_foreign_key "access_tokens", "users" add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" add_foreign_key "document_generation_events", "submitters" diff --git a/lib/auth_with_token_strategy.rb b/lib/auth_with_token_strategy.rb index 4b7f6b0b..391928be 100644 --- a/lib/auth_with_token_strategy.rb +++ b/lib/auth_with_token_strategy.rb @@ -6,9 +6,9 @@ class AuthWithTokenStrategy < Devise::Strategies::Base end def authenticate! - payload = JsonWebToken.decode(request.headers['X-Auth-Token']) + sha256 = Digest::SHA256.hexdigest(request.headers['X-Auth-Token']) - user = User.find_by(uuid: payload['uuid']) + user = User.joins(:access_token).find_by(access_token: { sha256: }) if user success!(user)