File: carrier_wave_extensions.rb

package info (click to toggle)
ruby-lockbox 2.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 224 kB
  • sloc: ruby: 1,447; makefile: 4
file content (114 lines) | stat: -rw-r--r-- 3,710 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
module Lockbox
  module CarrierWaveExtensions
    def encrypt(**options)
      class_eval do
        # uses same hook as process (before cache)
        # processing can be disabled, so better to keep separate
        before :cache, :encrypt

        define_singleton_method :lockbox_options do
          options
        end

        def encrypt(file)
          # safety check
          # see CarrierWave::Uploader::Cache#cache!
          raise Lockbox::Error, "Expected files to be equal. Please report an issue." unless file && @file && file == @file

          # processors in CarrierWave move updated file to current_path
          # however, this causes versions to use the processed file
          # we only want to change the file for the current version
          @file = CarrierWave::SanitizedFile.new(lockbox_notify("encrypt_file") { lockbox.encrypt_io(file) })
        end

        # TODO safe to memoize?
        def read
          r = super
          lockbox_notify("decrypt_file") { lockbox.decrypt(r) } if r
        end

        # use size of plaintext since read and content type use plaintext
        def size
          read.bytesize
        end

        def content_type
          if Gem::Version.new(CarrierWave::VERSION) >= Gem::Version.new("2.2.1")
            # based on CarrierWave::SanitizedFile#marcel_magic_content_type
            Marcel::Magic.by_magic(read).try(:type) || "invalid/invalid"
          elsif CarrierWave::VERSION.to_i >= 2
            # based on CarrierWave::SanitizedFile#mime_magic_content_type
            MimeMagic.by_magic(read).try(:type) || "invalid/invalid"
          else
            # uses filename
            super
          end
        end

        # disable processing since already processed
        def rotate_encryption!
          io = Lockbox::IO.new(read)
          io.original_filename = file.filename
          previous_value = enable_processing
          begin
            self.enable_processing = false
            store!(io)
          ensure
            self.enable_processing = previous_value
          end
        end

        private

        define_method :lockbox do
          @lockbox ||= begin
            table = model ? model.class.table_name : "_uploader"
            attribute = lockbox_name

            Utils.build_box(self, options, table, attribute)
          end
        end

        # for mounted uploaders, use mounted name
        # for others, use uploader name
        def lockbox_name
          if mounted_as
            mounted_as.to_s
          else
            uploader = self
            while uploader.parent_version
              uploader = uploader.parent_version
            end
            uploader.class.name.delete_suffix("Uploader").underscore
          end
        end

        # Active Support notifications so it's easier
        # to see when files are encrypted and decrypted
        def lockbox_notify(type)
          if defined?(ActiveSupport::Notifications)
            name = lockbox_name

            # get version
            version, _ = parent_version && parent_version.versions.find { |k, v| v == self }
            name = "#{name} #{version} version" if version

            ActiveSupport::Notifications.instrument("#{type}.lockbox", {name: name}) do
              yield
            end
          else
            yield
          end
        end
      end
    end
  end
end

if CarrierWave::VERSION.to_i > 3
  raise Lockbox::Error, "CarrierWave #{CarrierWave::VERSION} not supported in this version of Lockbox"
elsif CarrierWave::VERSION.to_i < 1
  raise Lockbox::Error, "CarrierWave #{CarrierWave::VERSION} not supported"
end

CarrierWave::Uploader::Base.extend(Lockbox::CarrierWaveExtensions)