active_storage_encryption 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +12 -0
  3. data/.github/workflows/ci.yml +75 -0
  4. data/.gitignore +14 -0
  5. data/.ruby-version +1 -0
  6. data/.standard.yml +1 -0
  7. data/Appraisals +2 -0
  8. data/Gemfile +9 -0
  9. data/README.md +2 -0
  10. data/active_storage_encryption.gemspec +47 -0
  11. data/gemfiles/rails_7.gemfile +1 -0
  12. data/gemfiles/rails_7.gemfile.lock +78 -1
  13. data/gemfiles/rails_8.gemfile +1 -0
  14. data/gemfiles/rails_8.gemfile.lock +78 -1
  15. data/lib/active_storage/service/encrypted_gcs_service.rb +10 -0
  16. data/lib/active_storage_encryption/encrypted_blob_proxy_controller.rb +1 -1
  17. data/lib/active_storage_encryption/encrypted_gcs_service.rb +158 -0
  18. data/lib/active_storage_encryption/engine.rb +4 -0
  19. data/lib/active_storage_encryption/overrides.rb +33 -5
  20. data/lib/active_storage_encryption/private_url_policy.rb +1 -1
  21. data/lib/active_storage_encryption/version.rb +1 -1
  22. data/lib/active_storage_encryption.rb +1 -0
  23. data/lib/generators/add_encryption_key_to_active_storage_blobs.rb.erb +9 -0
  24. data/lib/generators/install_generator.rb +25 -0
  25. data/test/dummy/app/assets/images/.keep +0 -0
  26. data/test/dummy/app/controllers/concerns/.keep +0 -0
  27. data/test/dummy/app/models/concerns/.keep +0 -0
  28. data/test/dummy/app/models/user.rb +5 -0
  29. data/test/dummy/config/environments/test.rb +2 -0
  30. data/test/dummy/config/storage.yml +3 -0
  31. data/test/dummy/db/migrate/20250428093315_create_users.rb +7 -0
  32. data/test/dummy/db/schema.rb +6 -3
  33. data/test/dummy/lib/assets/.keep +0 -0
  34. data/test/dummy/log/.keep +0 -0
  35. data/test/integration/.keep +0 -0
  36. data/test/lib/encrypted_gcs_service_test.rb +201 -0
  37. data/test/lib/encrypted_s3_service_test.rb +4 -1
  38. data/test/lib/overrides_test.rb +349 -0
  39. metadata +52 -127
  40. data/test/dummy/log/development.log +0 -304
  41. data/test/dummy/log/test.log +0 -66969
  42. data/test/dummy/storage/0a/mt/0amtaps713liftrtbxt9h998epz4 +0 -0
  43. data/test/dummy/storage/0b/93/0b93pygovuunam1a3ovzwmrbuw2x +0 -0
  44. data/test/dummy/storage/0m/3s/0m3s7r3nboblijr1jxlnvm3p3l4b +0 -0
  45. data/test/dummy/storage/0o/9s/0o9s4ctbpu757qh7ucyony0itek4 +0 -0
  46. data/test/dummy/storage/1e/q6/1eq646og0wazgfw7bwjqz2uem0g4 +0 -0
  47. data/test/dummy/storage/1n/o3/1no30cpwrm727bm6arvb7zxagdg1 +0 -0
  48. data/test/dummy/storage/1x/6w/1x6wsoq3pew17reztwax78lrr3hc +0 -0
  49. data/test/dummy/storage/28/de/28deswrv89c9f2tk7dz1l5uovd4r +0 -0
  50. data/test/dummy/storage/2h/sd/2hsd1mh20c6os2nzyoicfyymhwev +0 -0
  51. data/test/dummy/storage/2t/ni/2tnidhdk4c6cj0tnw3jiw88dgs4g +0 -0
  52. data/test/dummy/storage/2v/e0/2ve0555nluisy2el5cf4txzgae3j +0 -0
  53. data/test/dummy/storage/2z/c5/2zc5mj8g0o9l7mfnim0vs4v48xd6 +0 -0
  54. data/test/dummy/storage/34/xc/34xc9hk74dm9227d6mhgfcfxl4ue +0 -0
  55. data/test/dummy/storage/3z/0t/3z0tnve7ivrq0qyrvfhfzztjhjqs +0 -0
  56. data/test/dummy/storage/49/14/4914188q1dptpw4po91cp54f32bg +0 -0
  57. data/test/dummy/storage/4c/74/4c7412lfz0pm2ocg6u01h67bnsch +0 -0
  58. data/test/dummy/storage/52/qf/52qfbgjlf3gor3agsyrt09t19o55 +0 -0
  59. data/test/dummy/storage/57/go/57gok1uc4ebc3ugrjrje4lpe1ram +0 -0
  60. data/test/dummy/storage/5f/dv/5fdvt6tu1mkyajbz4hbxbw6fpt9w +0 -0
  61. data/test/dummy/storage/5x/b7/5xb7zzi66fi5f6yrn09pq4ogb9wo +0 -0
  62. data/test/dummy/storage/6m/vr/6mvr1fr5it125tm4vahjw6bv9wkz +0 -0
  63. data/test/dummy/storage/7b/hb/7bhbdxqn67lape1f49jqfktcei4n +0 -0
  64. data/test/dummy/storage/7n/4v/7n4vpm1q14y4qffc4jj78m036gtw +0 -0
  65. data/test/dummy/storage/7q/ku/7qkufbjwbbqwnf89uciosleixnew +0 -0
  66. data/test/dummy/storage/8l/5v/8l5vb4o02hx46s5qohfn5to945p3 +0 -0
  67. data/test/dummy/storage/8q/pu/8qpun3f8vzl7auxajvqyq8f48ngw +0 -0
  68. data/test/dummy/storage/8w/ag/8wag4ptmox207h7mobamk0tcebwx +0 -0
  69. data/test/dummy/storage/8w/v8/8wv8lrhsw4s2r6guh1csd3jd89ii +0 -0
  70. data/test/dummy/storage/9b/c6/9bc6wlpfnqdywpnxgeoin3w9b5ch +0 -0
  71. data/test/dummy/storage/9l/wk/9lwkt21k5iburdaitbwliw7krtwt +0 -0
  72. data/test/dummy/storage/9p/0v/9p0vgfw3l2854k7so3rp33rmyh7p +0 -0
  73. data/test/dummy/storage/9r/sy/9rsya3r6syft34qz24g1h4u4qq44 +0 -0
  74. data/test/dummy/storage/9s/es/9seslusr46xjf3mfzq10hkp13kc1 +0 -0
  75. data/test/dummy/storage/9t/nv/9tnvn5v52fkvurpgszf4gco78t5h +0 -0
  76. data/test/dummy/storage/9u/to/9utokgxyu6xyovandu7pjhogoaqp +0 -0
  77. data/test/dummy/storage/9w/a4/9wa4c20p4dvm1cd5thnv9f7ei13w +0 -0
  78. data/test/dummy/storage/at/kg/atkgs5gwz2xdv9lvqftsg6p7gcpu +0 -0
  79. data/test/dummy/storage/at/qo/atqomgf3rpb2f6e1tq1yn2xqzojv +0 -0
  80. data/test/dummy/storage/ba/lq/balqtije6kf82ht4lr70ajaae9kc +0 -0
  81. data/test/dummy/storage/bf/i1/bfi1ij9rygr6lkx1r0lhgi8o5smx +0 -0
  82. data/test/dummy/storage/bg/ye/bgyenotrv3aj6lk88edwv0c41pfj +0 -0
  83. data/test/dummy/storage/bu/xe/buxed4b1l78kcax53fa37awm9ywk +0 -0
  84. data/test/dummy/storage/d2/c1/d2c11nhikb474oq3q7so0xbhukvj +0 -0
  85. data/test/dummy/storage/development.sqlite3 +0 -0
  86. data/test/dummy/storage/dk/hy/dkhybxn2o27a8xgvfhsxpgqxa1zf +0 -0
  87. data/test/dummy/storage/e7/2n/e72nz5cz3wf6qvh4dw4qfnw6ucog +0 -0
  88. data/test/dummy/storage/eo/4q/eo4qn68m7al0ehhe0s23ycuzkjto +0 -0
  89. data/test/dummy/storage/ew/8s/ew8sejdsx8ddmrzkvfa37ebz1ts1 +0 -0
  90. data/test/dummy/storage/f8/q1/f8q1kpg2tou8ru0afj8d2gy6ym5p +0 -0
  91. data/test/dummy/storage/fr/55/fr558uhp1k93jzhb4butyi2ry51t +0 -0
  92. data/test/dummy/storage/g4/nh/g4nhx1zxbeiegqpgn8ppsl1yhm0t +0 -0
  93. data/test/dummy/storage/gg/r5/ggr51egxhqfh4w5eluzs47qceb76 +0 -0
  94. data/test/dummy/storage/gh/ua/ghuaagralqmjy8rkbwmuv3010lvs +0 -0
  95. data/test/dummy/storage/gx/uh/gxuhmf52ufli3m7ng8irp8ghxa1v +0 -0
  96. data/test/dummy/storage/h0/m1/h0m1emy251xus1d9qh6u25dzy18o +0 -0
  97. data/test/dummy/storage/hh/kc/hhkc2q8paptyvhw2m5hlwylhtfo5 +0 -0
  98. data/test/dummy/storage/hq/0q/hq0q04kr6qzrp0qaee8rehcp2tzx +0 -0
  99. data/test/dummy/storage/ii/g1/iig1ge3fsjitai4g2fkq4qt369wh +0 -0
  100. data/test/dummy/storage/io/f0/iof0mv7w8qjd6m826g52pzyxedet +0 -0
  101. data/test/dummy/storage/jk/2i/jk2ifmx6ac35ubk3esufnm6bn1m1 +0 -0
  102. data/test/dummy/storage/jw/4t/jw4trdeyfkw3j8z70xcnr9a7gqe5 +0 -0
  103. data/test/dummy/storage/ke/k2/kek24leksglm1rs2a78mfmot0p3s +0 -0
  104. data/test/dummy/storage/kh/6d/kh6doaxxwxiyes0yqz2dmmpajkzv +0 -0
  105. data/test/dummy/storage/kj/7n/kj7nookjhisagd80z8hlv3wn50am +0 -0
  106. data/test/dummy/storage/kq/lf/kqlf5udtrgrk4v55qodxyt6i68p8 +0 -0
  107. data/test/dummy/storage/ky/33/ky334jbo8eb08pj9qbe919iz91mh +0 -0
  108. data/test/dummy/storage/lt/zw/ltzw4lur2bheit1273ogpfzhv7j1 +0 -0
  109. data/test/dummy/storage/m2/ve/m2vejmyttn1ium81dopppom6vum6 +0 -0
  110. data/test/dummy/storage/m8/d4/m8d4r9iauedq8wlpvnx1f3ou0jwg +0 -0
  111. data/test/dummy/storage/m9/ee/m9eetioklzatyff94gq0vn1cga1n +0 -0
  112. data/test/dummy/storage/ma/v0/mav084zvmyoh1a8i7dcwqy2aaoi9 +0 -0
  113. data/test/dummy/storage/mg/pa/mgpauiu02i28j3poef65k3q0gfpw +0 -0
  114. data/test/dummy/storage/mm/8g/mm8gp5evncb1ol1lj2jlmra2ixij +0 -0
  115. data/test/dummy/storage/mm/d2/mmd21x8c1amgnidzw0wowiwug4g3 +0 -0
  116. data/test/dummy/storage/n2/qr/n2qro0y9heko9cwxlf10wiqiipsw +0 -0
  117. data/test/dummy/storage/n8/b7/n8b7b7qgu6jtw577dnn10jrrmszs +0 -0
  118. data/test/dummy/storage/n8/p2/n8p2ine0qqhphn09kqtxco4y7g0a +0 -0
  119. data/test/dummy/storage/nk/vh/nkvhgk7snpdy2ak6k02htxx9swp7 +0 -0
  120. data/test/dummy/storage/nn/s0/nns0nggo0x645ytco52adnsi4myp +0 -0
  121. data/test/dummy/storage/nu/kz/nukzl7cckkzh68i7kyjkm9mzw7c0 +0 -0
  122. data/test/dummy/storage/nv/8v/nv8vyoghcde1yr1bjpsw4327qt7s +0 -0
  123. data/test/dummy/storage/of/on/ofonhf1gs26k3dpj6o7b0ktzfowh +0 -0
  124. data/test/dummy/storage/pl/pf/plpfs59hvdoogj9gdweqta36csqn +0 -0
  125. data/test/dummy/storage/q5/g5/q5g55ekmscu10pzfw6q4syigt81g +0 -0
  126. data/test/dummy/storage/q5/kc/q5kcr9twyb9v4mh31pay0t7nkuwu +0 -0
  127. data/test/dummy/storage/qa/xd/qaxdngi74r52ahqg1pz8hjddeajc +0 -0
  128. data/test/dummy/storage/r7/5v/r75vadn34ak53vinylgnfdl1s8rt +0 -0
  129. data/test/dummy/storage/rj/rg/rjrghnyzyvxpkjw1a57mrloz72x1 +0 -0
  130. data/test/dummy/storage/se/h7/seh7eorfoanpp6de62pubv7kyu1a +0 -0
  131. data/test/dummy/storage/sj/i1/sji1oj12soz2fcjcoz0gejvzo8to +0 -0
  132. data/test/dummy/storage/sn/2r/sn2rku9thay4hbcbt926an69maku +0 -0
  133. data/test/dummy/storage/sw/jm/swjmbmxou3tnarcirxc6gdycxh91 +0 -0
  134. data/test/dummy/storage/sz/mq/szmqlydvpgqaw7p3v0wh444wtcif +0 -0
  135. data/test/dummy/storage/test.sqlite3 +0 -0
  136. data/test/dummy/storage/tg/by/tgbyrdvg94ivhhy2z59e8l9fod10 +0 -0
  137. data/test/dummy/storage/u5/vm/u5vmz08tuayqggd436et8fiaeml1 +0 -0
  138. data/test/dummy/storage/u6/pf/u6pf4yky0vbmvid3fa3lm4lre68g +0 -0
  139. data/test/dummy/storage/ub/ql/ubqlmlilt8ujgdpngcm1zae41kgy +0 -0
  140. data/test/dummy/storage/un/29/un29e9khqism72ag27ojccmn5sds +0 -0
  141. data/test/dummy/storage/ux/ns/uxnsvuk4rr1p67n1oq6tmraz0gaw +0 -0
  142. data/test/dummy/storage/v1/qo/v1qor0zxg3lctk9mbwyos3oag9gj +0 -0
  143. data/test/dummy/storage/v8/ok/v8okmd7374w1obna13a7anllx2vu +0 -0
  144. data/test/dummy/storage/vd/tf/vdtfmz2ctis3dr1r35do9bow2xj5 +0 -0
  145. data/test/dummy/storage/vo/dg/vodgq1inccnujjt3auber7tt8w8o +0 -0
  146. data/test/dummy/storage/vp/oe/vpoeiq00tf9pk0jcjlccomkju1zc +0 -0
  147. data/test/dummy/storage/vu/kg/vukgoj6qf96bhealui2yaeyn4n72 +0 -0
  148. data/test/dummy/storage/w7/2z/w72zoqu7v6v6jp0tpy671dcbvpow +0 -0
  149. data/test/dummy/storage/wa/3f/wa3fncsnozc6n4xfu32gw34geqcd +0 -0
  150. data/test/dummy/storage/wy/ix/wyixbqx3f6a4agb8bjhrtpblpaua +0 -0
  151. data/test/dummy/storage/xd/st/xdsttma3tqt7mex0vhp1vsm3dq16 +0 -0
  152. data/test/dummy/storage/xv/ej/xvejm2e064bnpunx3nmktaqs0x90 +0 -0
  153. data/test/dummy/storage/xx/py/xxpyyodssq2xmp57qrtvuw0wchwk +0 -0
  154. data/test/dummy/storage/xz/ik/xzikejc5sohi3zexa93s9xmg4jst +0 -0
  155. data/test/dummy/storage/y4/g8/y4g8teo86blcv0zysa2d2jawvk6i +0 -0
  156. data/test/dummy/storage/y9/58/y958xli6aoktx1ehuyjc1k8dcbzv +0 -0
  157. data/test/dummy/storage/yj/lw/yjlw8bf70iujb16deja8ae43rqbc +0 -0
  158. data/test/dummy/storage/z3/qy/z3qyb9avbucwhxa8909rpfued0y5 +0 -0
  159. data/test/dummy/storage/zr/wu/zrwudcg4kgo7r0jemszuzok8grqp +0 -0
  160. data/test/dummy/tmp/local_secret.txt +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f97954b59908255d0d2e09943e111ca33af803ca47d3a9af06a44e23064f725
4
- data.tar.gz: 700a8909d6492c8a8a8633c24a15418428c5e740d15adeef2cfcb15dcf872ac9
3
+ metadata.gz: 6f34184e53ab51b15143acc6fd7bbc2ea0e43a4cc4c0b0d87c065de2631298fb
4
+ data.tar.gz: 8329f26f7141a0762bb0488995bdf219ff01c00d9b374b4cdecc7af895bded11
5
5
  SHA512:
6
- metadata.gz: 5eef06c92277075e3b5b9c5b4421f6b8352956b48f29b442d70b777ce737326f0470a728903ae1a42994792deb2d026b30b7497ea01c9ed723965e2e03c0d0d9
7
- data.tar.gz: d94575af669034bccf27f41de435c44219f247d71c8d19e3c24d27e0af5301e55e53afccd141e1c5047921880836380aa414f628f4602cafbce82831ceb35d5a
6
+ metadata.gz: 30d7ba6406ec77a7521cc47ea24b858e0de4502644516c3ea5a54b025e24ffe305b21f4fcf3244f1361c2fbedcc79f8dc8b8ce6a0e0e3558a202e1e21941a295
7
+ data.tar.gz: 71bf3a1c8ee30daee4bdb43bd8703b2c530e67fb0e68078fc07d208e266d1285c8f390392e6539afaaea839c3fa62e2b2cef46b8a863c4d57409d1ebe399c392
@@ -0,0 +1,12 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ open-pull-requests-limit: 10
8
+ - package-ecosystem: github-actions
9
+ directory: "/"
10
+ schedule:
11
+ interval: daily
12
+ open-pull-requests-limit: 10
@@ -0,0 +1,75 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [ main ]
7
+
8
+ jobs:
9
+ lint:
10
+ name: "Lint"
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - name: Checkout code
14
+ uses: actions/checkout@v4
15
+
16
+ # Note: Appraisals for Rails 7 and Rails 8 differ in minimum Ruby version: 3.1.0+ vs 3.2.2+
17
+ # So the version of Ruby to use here is the version that is able to run all Appraisals
18
+ - name: Set up Ruby
19
+ uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: 3.2.2
22
+ bundler-cache: true
23
+
24
+ - name: Lint code for consistent style
25
+ run: bundle exec standardrb
26
+
27
+ test_rails7:
28
+ name: "Tests (Rails 7)"
29
+ runs-on: ubuntu-latest
30
+ env:
31
+ BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/rails_7.gemfile
32
+ steps:
33
+ - name: Install packages
34
+ run: sudo apt-get update && sudo apt-get install --no-install-recommends -y curl libjemalloc2 sqlite3
35
+
36
+ - name: Checkout code
37
+ uses: actions/checkout@v4
38
+
39
+ - name: Set up Ruby
40
+ uses: ruby/setup-ruby@v1
41
+ with:
42
+ ruby-version: 3.2.2
43
+ bundler-cache: true
44
+
45
+ - name: Run tests
46
+ env:
47
+ RAILS_ENV: test
48
+ AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
49
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
50
+ run: bin/rails app:test
51
+
52
+ test_rails_8:
53
+ name: "Tests (Rails 8)"
54
+ runs-on: ubuntu-latest
55
+ env:
56
+ BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/rails_8.gemfile
57
+ steps:
58
+ - name: Install packages
59
+ run: sudo apt-get update && sudo apt-get install --no-install-recommends -y curl libjemalloc2 sqlite3
60
+
61
+ - name: Checkout code
62
+ uses: actions/checkout@v4
63
+
64
+ - name: Set up Ruby
65
+ uses: ruby/setup-ruby@v1
66
+ with:
67
+ ruby-version: 3.2.2
68
+ bundler-cache: true
69
+
70
+ - name: Run tests
71
+ env:
72
+ RAILS_ENV: test
73
+ AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
74
+ AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
75
+ run: bin/rails app:test
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /doc/
3
+ /log/*.log
4
+ /pkg/
5
+ /tmp/
6
+ /test/dummy/db/*.sqlite3
7
+ /test/dummy/db/*.sqlite3-*
8
+ /test/dummy/log/*.log
9
+ /test/dummy/storage/
10
+ /test/dummy/tmp/
11
+
12
+ # The Bundler lockfile should not be cached because its contents is arch-dependent
13
+ Gemfile.lock
14
+ .DS_Store
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.2
data/.standard.yml ADDED
@@ -0,0 +1 @@
1
+ ruby_version: 3.1
data/Appraisals CHANGED
@@ -1,7 +1,9 @@
1
1
  appraise "rails-7" do
2
2
  gem "rails", "< 8.0"
3
+ gem "stringio"
3
4
  end
4
5
 
5
6
  appraise "rails-8" do
6
7
  gem "rails", ">= 8.0"
8
+ gem "stringio"
7
9
  end
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in active_storage_encryption.gemspec.
6
+ gemspec
7
+
8
+ # Start debugger with binding.b [https://github.com/ruby/debug]
9
+ # gem "debug", ">= 1.0.0"
data/README.md CHANGED
@@ -113,6 +113,8 @@ Implementation details:
113
113
  * `x-amz-server-side-encryption-customer-key`
114
114
  * `x-amz-server-side-encryption-customer-key-MD5`
115
115
 
116
+ While S3 allows the `x-amz-server-side-encryption-customer-key-MD5` to be added to the signed URL for PUT, the value of that header gets removed from the signature due to the process called "hoisting" - which occurs during the signing of the URL. So your client _may_ override the encryption key you give it forcibly, by replacing the `x-amz-server-side-encryption-customer-key` and `x-amz-server-side-encryption-customer-key-MD5`. This can produce Blobs encrypted with a key you do not have. If you want to exclude the possibility of this, you need to perform an integrity check on your uploads. The integrity check will fail if the encryption key has been overridden in this manner, and you can then destroy the Blob. This problem has been reported to AWS.
117
+
116
118
  ### EncryptedDiskSevice - Filesystem
117
119
 
118
120
  Can be used instead of the cloud services in development, or on the server if desired. The service will use AES-256-GCM encryption, with a way to switch to a different/more modern encryption scheme in the future.
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/active_storage_encryption/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "active_storage_encryption"
7
+ spec.version = ActiveStorageEncryption::VERSION
8
+ spec.authors = ["Julik Tarkhanov", "Sebastian van Hesteren"]
9
+ spec.email = ["me@julik.nl"]
10
+ spec.homepage = "https://github.com/cheddar-me/active_storage_encryption"
11
+ spec.summary = "Customer-supplied encryption key support for ActiveStorage blobs."
12
+ spec.description = "Adds customer-supplied encryption keys to storage services."
13
+ spec.license = "MIT"
14
+ spec.required_ruby_version = ">= 3.1.0"
15
+
16
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the "allowed_push_host"
17
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
18
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
19
+
20
+ # The homepage link on rubygems.org only appears if you add homepage_uri. Just spec.homepage is not enough.
21
+ spec.metadata["homepage_uri"] = spec.homepage
22
+ spec.metadata["source_code_uri"] = spec.homepage
23
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
24
+
25
+ # Do not remove any files from the gemspec - tests are useful because people can read them
26
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
27
+ `git ls-files -z`.split("\x0")
28
+ end
29
+
30
+ spec.add_dependency "rails", ">= 7.2.2.1"
31
+ spec.add_dependency "block_cipher_kit", ">= 0.0.4"
32
+ spec.add_dependency "serve_byte_range", "~> 1.0"
33
+ spec.add_dependency "activestorage"
34
+
35
+ # Testing with cloud services
36
+ spec.add_development_dependency "aws-sdk-s3"
37
+ spec.add_development_dependency "net-http"
38
+ spec.add_development_dependency "google-cloud-storage"
39
+
40
+ # Code formatting, linting and testing
41
+ spec.add_development_dependency "sqlite3"
42
+ spec.add_development_dependency "standard", ">= 1.35.1"
43
+ spec.add_development_dependency "appraisal"
44
+ spec.add_development_dependency "magic_frozen_string_literal"
45
+ spec.add_development_dependency "rake"
46
+ spec.add_development_dependency "pry"
47
+ end
@@ -3,5 +3,6 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "rails", "< 8.0"
6
+ gem "stringio"
6
7
 
7
8
  gemspec path: "../"
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- active_storage_encryption (0.2.0)
4
+ active_storage_encryption (0.3.0)
5
5
  activestorage
6
6
  block_cipher_kit (>= 0.0.4)
7
7
  rails (>= 7.2.2.1)
@@ -81,6 +81,8 @@ GEM
81
81
  minitest (>= 5.1)
82
82
  securerandom (>= 0.3)
83
83
  tzinfo (~> 2.0, >= 2.0.5)
84
+ addressable (2.8.7)
85
+ public_suffix (>= 2.0.2, < 7.0)
84
86
  appraisal (2.5.0)
85
87
  bundler
86
88
  rake
@@ -108,14 +110,63 @@ GEM
108
110
  bigdecimal (3.1.9)
109
111
  block_cipher_kit (0.0.4)
110
112
  builder (3.3.0)
113
+ coderay (1.1.3)
111
114
  concurrent-ruby (1.3.5)
112
115
  connection_pool (2.5.0)
113
116
  crass (1.0.6)
114
117
  date (3.4.1)
118
+ declarative (0.0.20)
119
+ digest-crc (0.7.0)
120
+ rake (>= 12.0.0, < 14.0.0)
115
121
  drb (2.2.1)
116
122
  erubi (1.13.1)
123
+ faraday (2.13.0)
124
+ faraday-net_http (>= 2.0, < 3.5)
125
+ json
126
+ logger
127
+ faraday-net_http (3.4.0)
128
+ net-http (>= 0.5.0)
117
129
  globalid (1.2.1)
118
130
  activesupport (>= 6.1)
131
+ google-apis-core (0.16.0)
132
+ addressable (~> 2.5, >= 2.5.1)
133
+ googleauth (~> 1.9)
134
+ httpclient (>= 2.8.3, < 3.a)
135
+ mini_mime (~> 1.0)
136
+ mutex_m
137
+ representable (~> 3.0)
138
+ retriable (>= 2.0, < 4.a)
139
+ google-apis-iamcredentials_v1 (0.22.0)
140
+ google-apis-core (>= 0.15.0, < 2.a)
141
+ google-apis-storage_v1 (0.50.0)
142
+ google-apis-core (>= 0.15.0, < 2.a)
143
+ google-cloud-core (1.8.0)
144
+ google-cloud-env (>= 1.0, < 3.a)
145
+ google-cloud-errors (~> 1.0)
146
+ google-cloud-env (2.2.2)
147
+ base64 (~> 0.2)
148
+ faraday (>= 1.0, < 3.a)
149
+ google-cloud-errors (1.5.0)
150
+ google-cloud-storage (1.56.0)
151
+ addressable (~> 2.8)
152
+ digest-crc (~> 0.4)
153
+ google-apis-core (~> 0.13)
154
+ google-apis-iamcredentials_v1 (~> 0.18)
155
+ google-apis-storage_v1 (>= 0.42)
156
+ google-cloud-core (~> 1.6)
157
+ googleauth (~> 1.9)
158
+ mini_mime (~> 1.0)
159
+ google-logging-utils (0.1.0)
160
+ googleauth (1.14.0)
161
+ faraday (>= 1.0, < 3.a)
162
+ google-cloud-env (~> 2.2)
163
+ google-logging-utils (~> 0.1)
164
+ jwt (>= 1.4, < 3.0)
165
+ multi_json (~> 1.11)
166
+ os (>= 0.9, < 2.0)
167
+ signet (>= 0.16, < 2.a)
168
+ httpclient (2.9.0)
169
+ mutex_m
119
170
  i18n (1.14.7)
120
171
  concurrent-ruby (~> 1.0)
121
172
  io-console (0.8.0)
@@ -125,6 +176,8 @@ GEM
125
176
  reline (>= 0.4.2)
126
177
  jmespath (1.6.2)
127
178
  json (2.10.1)
179
+ jwt (2.10.1)
180
+ base64
128
181
  language_server-protocol (3.17.0.4)
129
182
  lint_roller (1.1.0)
130
183
  logger (1.6.6)
@@ -138,8 +191,11 @@ GEM
138
191
  net-pop
139
192
  net-smtp
140
193
  marcel (1.0.4)
194
+ method_source (1.1.0)
141
195
  mini_mime (1.1.5)
142
196
  minitest (5.25.4)
197
+ multi_json (1.15.0)
198
+ mutex_m (0.3.0)
143
199
  net-http (0.6.0)
144
200
  uri
145
201
  net-imap (0.5.6)
@@ -158,6 +214,7 @@ GEM
158
214
  racc (~> 1.4)
159
215
  nokogiri (1.18.3-x86_64-linux-gnu)
160
216
  racc (~> 1.4)
217
+ os (1.1.4)
161
218
  parallel (1.26.3)
162
219
  parser (3.3.7.1)
163
220
  ast (~> 2.4.1)
@@ -165,9 +222,13 @@ GEM
165
222
  pp (0.6.2)
166
223
  prettyprint
167
224
  prettyprint (0.2.0)
225
+ pry (0.15.2)
226
+ coderay (~> 1.1)
227
+ method_source (~> 1.0)
168
228
  psych (5.2.3)
169
229
  date
170
230
  stringio
231
+ public_suffix (6.0.1)
171
232
  racc (1.8.1)
172
233
  rack (3.1.11)
173
234
  rack-session (2.1.0)
@@ -213,6 +274,11 @@ GEM
213
274
  regexp_parser (2.10.0)
214
275
  reline (0.6.0)
215
276
  io-console (~> 0.5)
277
+ representable (3.2.0)
278
+ declarative (< 0.1.0)
279
+ trailblazer-option (>= 0.1.1, < 0.2.0)
280
+ uber (< 0.2.0)
281
+ retriable (3.1.2)
216
282
  rubocop (1.71.2)
217
283
  json (~> 2.3)
218
284
  language_server-protocol (>= 3.17.0)
@@ -232,6 +298,11 @@ GEM
232
298
  securerandom (0.4.1)
233
299
  serve_byte_range (1.0.0)
234
300
  rack (>= 1.0)
301
+ signet (0.19.0)
302
+ addressable (~> 2.8)
303
+ faraday (>= 0.17.5, < 3.a)
304
+ jwt (>= 1.5, < 3.0)
305
+ multi_json (~> 1.10)
235
306
  sqlite3 (2.6.0-arm64-darwin)
236
307
  sqlite3 (2.6.0-x86_64-darwin)
237
308
  sqlite3 (2.6.0-x86_64-linux-gnu)
@@ -250,8 +321,10 @@ GEM
250
321
  stringio (3.1.5)
251
322
  thor (1.3.2)
252
323
  timeout (0.4.3)
324
+ trailblazer-option (0.1.2)
253
325
  tzinfo (2.0.6)
254
326
  concurrent-ruby (~> 1.0)
327
+ uber (0.1.0)
255
328
  unicode-display_width (3.1.4)
256
329
  unicode-emoji (~> 4.0, >= 4.0.4)
257
330
  unicode-emoji (4.0.4)
@@ -265,6 +338,7 @@ GEM
265
338
 
266
339
  PLATFORMS
267
340
  arm64-darwin-21
341
+ arm64-darwin-23
268
342
  arm64-darwin-24
269
343
  x86_64-darwin
270
344
  x86_64-linux
@@ -273,12 +347,15 @@ DEPENDENCIES
273
347
  active_storage_encryption!
274
348
  appraisal
275
349
  aws-sdk-s3
350
+ google-cloud-storage
276
351
  magic_frozen_string_literal
277
352
  net-http
353
+ pry
278
354
  rails (< 8.0)
279
355
  rake
280
356
  sqlite3
281
357
  standard (>= 1.35.1)
358
+ stringio
282
359
 
283
360
  BUNDLED WITH
284
361
  2.5.11
@@ -3,5 +3,6 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "rails", ">= 8.0"
6
+ gem "stringio"
6
7
 
7
8
  gemspec path: "../"
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- active_storage_encryption (0.2.0)
4
+ active_storage_encryption (0.3.0)
5
5
  activestorage
6
6
  block_cipher_kit (>= 0.0.4)
7
7
  rails (>= 7.2.2.1)
@@ -81,6 +81,8 @@ GEM
81
81
  securerandom (>= 0.3)
82
82
  tzinfo (~> 2.0, >= 2.0.5)
83
83
  uri (>= 0.13.1)
84
+ addressable (2.8.7)
85
+ public_suffix (>= 2.0.2, < 7.0)
84
86
  appraisal (2.5.0)
85
87
  bundler
86
88
  rake
@@ -108,14 +110,63 @@ GEM
108
110
  bigdecimal (3.1.9)
109
111
  block_cipher_kit (0.0.4)
110
112
  builder (3.3.0)
113
+ coderay (1.1.3)
111
114
  concurrent-ruby (1.3.5)
112
115
  connection_pool (2.5.0)
113
116
  crass (1.0.6)
114
117
  date (3.4.1)
118
+ declarative (0.0.20)
119
+ digest-crc (0.7.0)
120
+ rake (>= 12.0.0, < 14.0.0)
115
121
  drb (2.2.1)
116
122
  erubi (1.13.1)
123
+ faraday (2.13.0)
124
+ faraday-net_http (>= 2.0, < 3.5)
125
+ json
126
+ logger
127
+ faraday-net_http (3.4.0)
128
+ net-http (>= 0.5.0)
117
129
  globalid (1.2.1)
118
130
  activesupport (>= 6.1)
131
+ google-apis-core (0.16.0)
132
+ addressable (~> 2.5, >= 2.5.1)
133
+ googleauth (~> 1.9)
134
+ httpclient (>= 2.8.3, < 3.a)
135
+ mini_mime (~> 1.0)
136
+ mutex_m
137
+ representable (~> 3.0)
138
+ retriable (>= 2.0, < 4.a)
139
+ google-apis-iamcredentials_v1 (0.22.0)
140
+ google-apis-core (>= 0.15.0, < 2.a)
141
+ google-apis-storage_v1 (0.50.0)
142
+ google-apis-core (>= 0.15.0, < 2.a)
143
+ google-cloud-core (1.8.0)
144
+ google-cloud-env (>= 1.0, < 3.a)
145
+ google-cloud-errors (~> 1.0)
146
+ google-cloud-env (2.2.2)
147
+ base64 (~> 0.2)
148
+ faraday (>= 1.0, < 3.a)
149
+ google-cloud-errors (1.5.0)
150
+ google-cloud-storage (1.56.0)
151
+ addressable (~> 2.8)
152
+ digest-crc (~> 0.4)
153
+ google-apis-core (~> 0.13)
154
+ google-apis-iamcredentials_v1 (~> 0.18)
155
+ google-apis-storage_v1 (>= 0.42)
156
+ google-cloud-core (~> 1.6)
157
+ googleauth (~> 1.9)
158
+ mini_mime (~> 1.0)
159
+ google-logging-utils (0.1.0)
160
+ googleauth (1.14.0)
161
+ faraday (>= 1.0, < 3.a)
162
+ google-cloud-env (~> 2.2)
163
+ google-logging-utils (~> 0.1)
164
+ jwt (>= 1.4, < 3.0)
165
+ multi_json (~> 1.11)
166
+ os (>= 0.9, < 2.0)
167
+ signet (>= 0.16, < 2.a)
168
+ httpclient (2.9.0)
169
+ mutex_m
119
170
  i18n (1.14.7)
120
171
  concurrent-ruby (~> 1.0)
121
172
  io-console (0.8.0)
@@ -125,6 +176,8 @@ GEM
125
176
  reline (>= 0.4.2)
126
177
  jmespath (1.6.2)
127
178
  json (2.10.1)
179
+ jwt (2.10.1)
180
+ base64
128
181
  language_server-protocol (3.17.0.4)
129
182
  lint_roller (1.1.0)
130
183
  logger (1.6.6)
@@ -138,8 +191,11 @@ GEM
138
191
  net-pop
139
192
  net-smtp
140
193
  marcel (1.0.4)
194
+ method_source (1.1.0)
141
195
  mini_mime (1.1.5)
142
196
  minitest (5.25.4)
197
+ multi_json (1.15.0)
198
+ mutex_m (0.3.0)
143
199
  net-http (0.6.0)
144
200
  uri
145
201
  net-imap (0.5.6)
@@ -158,6 +214,7 @@ GEM
158
214
  racc (~> 1.4)
159
215
  nokogiri (1.18.3-x86_64-linux-gnu)
160
216
  racc (~> 1.4)
217
+ os (1.1.4)
161
218
  parallel (1.26.3)
162
219
  parser (3.3.7.1)
163
220
  ast (~> 2.4.1)
@@ -165,9 +222,13 @@ GEM
165
222
  pp (0.6.2)
166
223
  prettyprint
167
224
  prettyprint (0.2.0)
225
+ pry (0.15.2)
226
+ coderay (~> 1.1)
227
+ method_source (~> 1.0)
168
228
  psych (5.2.3)
169
229
  date
170
230
  stringio
231
+ public_suffix (6.0.1)
171
232
  racc (1.8.1)
172
233
  rack (3.1.11)
173
234
  rack-session (2.1.0)
@@ -213,6 +274,11 @@ GEM
213
274
  regexp_parser (2.10.0)
214
275
  reline (0.6.0)
215
276
  io-console (~> 0.5)
277
+ representable (3.2.0)
278
+ declarative (< 0.1.0)
279
+ trailblazer-option (>= 0.1.1, < 0.2.0)
280
+ uber (< 0.2.0)
281
+ retriable (3.1.2)
216
282
  rubocop (1.71.2)
217
283
  json (~> 2.3)
218
284
  language_server-protocol (>= 3.17.0)
@@ -232,6 +298,11 @@ GEM
232
298
  securerandom (0.4.1)
233
299
  serve_byte_range (1.0.0)
234
300
  rack (>= 1.0)
301
+ signet (0.19.0)
302
+ addressable (~> 2.8)
303
+ faraday (>= 0.17.5, < 3.a)
304
+ jwt (>= 1.5, < 3.0)
305
+ multi_json (~> 1.10)
235
306
  sqlite3 (2.6.0-arm64-darwin)
236
307
  sqlite3 (2.6.0-x86_64-darwin)
237
308
  sqlite3 (2.6.0-x86_64-linux-gnu)
@@ -250,8 +321,10 @@ GEM
250
321
  stringio (3.1.5)
251
322
  thor (1.3.2)
252
323
  timeout (0.4.3)
324
+ trailblazer-option (0.1.2)
253
325
  tzinfo (2.0.6)
254
326
  concurrent-ruby (~> 1.0)
327
+ uber (0.1.0)
255
328
  unicode-display_width (3.1.4)
256
329
  unicode-emoji (~> 4.0, >= 4.0.4)
257
330
  unicode-emoji (4.0.4)
@@ -265,6 +338,7 @@ GEM
265
338
 
266
339
  PLATFORMS
267
340
  arm64-darwin-21
341
+ arm64-darwin-23
268
342
  arm64-darwin-24
269
343
  x86_64-darwin
270
344
  x86_64-linux
@@ -273,12 +347,15 @@ DEPENDENCIES
273
347
  active_storage_encryption!
274
348
  appraisal
275
349
  aws-sdk-s3
350
+ google-cloud-storage
276
351
  magic_frozen_string_literal
277
352
  net-http
353
+ pry
278
354
  rails (>= 8.0)
279
355
  rake
280
356
  sqlite3
281
357
  standard (>= 1.35.1)
358
+ stringio
282
359
 
283
360
  BUNDLED WITH
284
361
  2.5.11
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Needed so that Rails can find our service definition. It will perform the following
4
+ # steps. Given an "EncryptedDisk" value of the `service:` key in the YAML, it will:
5
+ #
6
+ # * Force-require a file at "active_storage/service/encrypted_disk", from any path on the $LOAD_PATH
7
+ # * Instantiate a class called "ActiveStorage::Service::EncryptedDiskService"
8
+ require_relative "../../active_storage_encryption"
9
+ class ActiveStorage::Service::EncryptedGCSService < ActiveStorageEncryption::EncryptedGCSService
10
+ end
@@ -105,7 +105,7 @@ class ActiveStorageEncryption::EncryptedBlobProxyController < ActionController::
105
105
  blob_etag = key.inspect # Strong ETags must be quoted
106
106
  status, headers, ranges_body = ServeByteRange.serve_ranges(request.env,
107
107
  resource_size: blob_byte_size,
108
- etag: blob_etag, # TODO
108
+ etag: blob_etag,
109
109
  resource_content_type: type,
110
110
  &streaming_proc)
111
111