@@ -18,50 +18,163 @@ namespace :db do
1818 end
1919 end
2020
21+ task import_from_existing_dump : [ :environment , :create ] do
22+ config = db_config
23+ env = { "PGPASSWORD" => config [ :password ] }
24+ puts "[1/1] Mounting backup on local database"
25+ system ( env , "pg_restore" , "--clean" , "--verbose" , "--no-acl" , "--no-owner" ,
26+ "--host" , config [ :host ] , "--username" , config [ :username ] , "--dbname" , config [ :database ] ,
27+ "tmp/latest.dump" )
28+ puts "Done."
29+ end
30+
2131 desc "Dumps the database to db/APP_NAME.dump"
2232 task dump : :environment do
23- cmd = nil
24- with_config do |app , host , db , user |
25- cmd = "pg_dump --host #{ host } --username #{ user } --verbose --clean --no-owner --no-acl --format=c #{ db } > #{ Rails . root } /db/#{ app } .dump"
26- end
33+ config = db_config
34+ env = { "PGPASSWORD" => config [ :password ] }
35+ cmd = "pg_dump --host #{ config [ :host ] } --username #{ config [ :username ] } --verbose --clean --no-owner --no-acl --format=c #{ config [ :database ] } > #{ Rails . root } /db/#{ config [ :app ] } .dump"
36+ puts cmd
37+ system ( env , cmd )
38+ end
39+
40+ desc "Dumps and compresses the database to db/APP_NAME.dump.gz"
41+ task dump_compressed : :environment do
42+ config = db_config
43+ env = { "PGPASSWORD" => config [ :password ] }
44+ cmd = "pg_dump --host #{ config [ :host ] } --username #{ config [ :username ] } --verbose --clean --no-owner --no-acl --format=c #{ config [ :database ] } | gzip > #{ Rails . root } /db/#{ config [ :app ] } .dump.gz"
2745 puts cmd
28- exec cmd
46+ system ( env , cmd )
2947 end
3048
3149 desc "Restores the database dump at db/APP_NAME.dump."
3250 task restore : :environment do
33- cmd = nil
34- with_config do | app , host , db , user |
35- cmd = "pg_restore --verbose --host #{ host } --username #{ user } --clean --no-owner --no-acl --dbname #{ db } #{ Rails . root } /db/ #{ app } .dump"
36- end
51+ abort "Refusing to restore dump in production." if Rails . env . production?
52+
53+ config = db_config
54+ env = { "PGPASSWORD" => config [ :password ] }
3755 Rake ::Task [ "db:drop" ] . invoke
3856 Rake ::Task [ "db:create" ] . invoke
57+ cmd = "pg_restore --verbose --host #{ config [ :host ] } --username #{ config [ :username ] } --clean --no-owner --no-acl --dbname #{ config [ :database ] } #{ Rails . root } /db/#{ config [ :app ] } .dump"
3958 puts cmd
40- exec cmd
59+ system ( env , cmd )
60+ end
61+
62+ desc "Restores the compressed dump at db/APP_NAME.dump.gz."
63+ task restore_compressed : :environment do
64+ abort "Refusing to restore compressed dump in production." if Rails . env . production?
65+
66+ config = db_config
67+ env = { "PGPASSWORD" => config [ :password ] }
68+ Rake ::Task [ "db:drop" ] . invoke
69+ Rake ::Task [ "db:create" ] . invoke
70+ cmd = "gunzip -c #{ Rails . root } /db/#{ config [ :app ] } .dump.gz | pg_restore --verbose --host #{ config [ :host ] } --username #{ config [ :username ] } --clean --no-owner --no-acl --dbname #{ config [ :database ] } "
71+ puts cmd
72+ system ( env , cmd )
73+ end
74+
75+ desc "Anonymizes sensitive data in the database"
76+ task anonymize : :environment do
77+ abort "Refusing to anonymize in production." if Rails . env . production?
78+
79+ puts "Anonymizing users..."
80+ User . find_each do |user |
81+ puts "Anonymizing User##{ user . id } (#{ user . username } )..."
82+ user . username = unique_value ( User , :username , "user#{ user . id } " , exclude_id : user . id )
83+ user . email = unique_value ( User , :email , "user#{ user . id } @example.invalid" , exclude_id : user . id )
84+ user . password = "password"
85+ user . password_confirmation = "password"
86+ user . reset_password_token = nil
87+ user . reset_password_sent_at = nil
88+ user . remember_created_at = nil
89+ user . current_sign_in_at = nil
90+ user . last_sign_in_at = nil
91+ user . current_sign_in_ip = nil
92+ user . last_sign_in_ip = nil
93+ user . provider = nil
94+ user . uid = nil
95+ user . discord_avatar_url = nil
96+ user . token = nil
97+ user . token_expiry = nil
98+ user . save! ( validate : false )
99+ end
100+
101+ puts "Scrubbing attachment filenames..."
102+ scrub_shrine_metadata ( Blueprint , :cover_picture_data , prefix : "cover" )
103+ scrub_shrine_metadata ( Blueprint , :blueprint_file_data , prefix : "blueprint" )
104+ scrub_shrine_metadata ( Picture , :picture_data , prefix : "picture" )
105+ scrub_active_storage_filenames
106+
107+ puts "Done."
41108 end
42109
43110 desc "Hides private information in the database"
44111 task privatize : :environment do
45- if Rails . env . development? # Don't want that in production whatever the reason
46- User . all . each do |u |
47- puts "Privatizing User##{ u . id } (#{ u . username } )..."
48- u . username = "User##{ u . id } "
49- u . email = "user##{ u . id } @test.com"
50- u . password = "password"
51- u . password_confirmation = "password"
52- u . save!
53- end
54- puts "Done."
55- end
112+ Rake ::Task [ "db:anonymize" ] . invoke
56113 end
57114
58115 private
59116
117+ def db_config
118+ config = Rails . configuration . database_configuration [ Rails . env ]
119+ {
120+ app : Rails . application . class . module_parent_name . underscore ,
121+ host : config [ "host" ] || "localhost" ,
122+ database : config [ "database" ] ,
123+ username : config [ "username" ] || config [ "user" ] || ENV [ "PG_USER" ] || "dev" ,
124+ password : config [ "password" ] || ENV [ "PG_PASS" ] || "password" ,
125+ }
126+ end
127+
60128 def with_config
61- yield Rails . application . class . module_parent_name . underscore ,
62- ActiveRecord ::Base . connection_config [ :host ] ,
63- ActiveRecord ::Base . connection_config [ :database ] ,
64- ActiveRecord ::Base . connection_config [ :username ]
129+ config = db_config
130+ yield config [ :app ] , config [ :host ] , config [ :database ] , config [ :username ]
131+ end
132+
133+ def scrub_shrine_metadata ( scope , column , prefix :)
134+ scope . find_each do |record |
135+ data = record . public_send ( column )
136+ next if data . blank?
137+
138+ parsed = begin
139+ JSON . parse ( data )
140+ rescue StandardError
141+ nil
142+ end
143+ next unless parsed . is_a? ( Hash )
144+
145+ metadata = parsed [ "metadata" ] || { }
146+ filename = metadata [ "filename" ] . to_s
147+ next if filename . empty?
148+
149+ ext = File . extname ( filename )
150+ metadata [ "filename" ] = "#{ prefix } -#{ record . id } #{ ext } "
151+ parsed [ "metadata" ] = metadata
152+ record . update_column ( column , parsed . to_json )
153+ end
154+ end
155+
156+ def scrub_active_storage_filenames
157+ return unless defined? ( ActiveStorage ::Blob )
158+
159+ ActiveStorage ::Blob . find_each do |blob |
160+ filename = blob . filename . to_s
161+ ext = File . extname ( filename )
162+ blob . update! ( filename : "file-#{ blob . id } #{ ext } " )
163+ end
164+ end
165+
166+ def unique_value ( scope , column , base , exclude_id :)
167+ value = base
168+ relation = scope . where . not ( id : exclude_id )
169+
170+ if base . include? ( "@" )
171+ local , domain = base . split ( "@" , 2 )
172+ value = "#{ local } -#{ SecureRandom . hex ( 3 ) } @#{ domain } " while relation . exists? ( column => value )
173+ else
174+ value = "#{ base } -#{ SecureRandom . hex ( 3 ) } " while relation . exists? ( column => value )
175+ end
176+
177+ value
65178 end
66179
67180 desc "Analyze and reindex the database"
0 commit comments