1
+
2
+ # (C) 2017 Vladimir Zhbanko
3
+ # Udemy Course: "Keep Your Secrets Under Your Control"
4
+
5
+ library(shiny )
6
+ library(DT )
7
+ library(openssl )
8
+ library(tidyverse )
9
+
10
+ # =======================================
11
+ # CONTENT #
12
+ # =======================================
13
+ # 1. generatePrivateKey
14
+ # 2. storeData
15
+ # 3. saveDataGlobal
16
+ # 4. decryptData
17
+ # 5. joinData
18
+ # 6. encryptData
19
+ # 7. inputPK
20
+ # 8. inputEData
21
+ # 9. oneRow
22
+ # 10. viewData
23
+ # 11. responses
24
+ # 12. downloadTable
25
+ # 13. downloadPrvKey
26
+ # 14. downloadPubKey
27
+ # 15. delKey
28
+ # 16. lineToDelete
29
+ # 17. eraseLine
30
+ # 18. importPassw
31
+ # 19. dataFromImport
32
+ # 20. dataFromSingleEntry
33
+ # 21. dataFromDecryption
34
+ # 22. viewPasswords
35
+ # =======================================
36
+ # DEFINE GLOBAL FUNCTIONS #
37
+ # =======================================
38
+ #
39
+ #
40
+ # --------------------------------------------------------------------
41
+ # function that generates private key and write it to the file
42
+ generatePrivateKey <- function (keyBits = 2099 , keyPath = " private.key" , passphrase = " udemy" ) {
43
+ openssl :: rsa_keygen(bits = keyBits ) %> %
44
+ write_pem(path = paste(Sys.Date(), keyPath , sep = " " ), password = passphrase )
45
+ }
46
+
47
+ # --------------------------------------------------------------------
48
+ # function that save data from DT() to csv file of the temp_folder directory and also check for duplicates
49
+ # -- use this function to store data to the file
50
+ # -- function also remove duplicate records from table
51
+ storeData <- function (data , directoryName , fileName ) {
52
+
53
+ # store only unique records
54
+ # non duplicates
55
+ nonDuplicate <- data [! duplicated(data ), ]
56
+ # Write the file to the local system
57
+ write.csv(
58
+ x = nonDuplicate ,
59
+ file = file.path(directoryName , fileName ),
60
+ row.names = FALSE , quote = FALSE , append = TRUE , col.names = FALSE
61
+ )
62
+ }
63
+
64
+ # --------------------------------------------------------------------
65
+ # function that write data to global directory called "responses"
66
+ # -- use this function to append data to the existing table
67
+ # -- data will be stored in the global object 'responses'
68
+ saveDataGlobal <- function (data ) {
69
+
70
+ if (exists(" responses" )) { # get data from global environment is it's exist there
71
+ responses <<- rbind(responses , data )
72
+ } else {
73
+ responses <<- data # <<- this saves to the global environment
74
+ }
75
+ }
76
+
77
+ # --------------------------------------------------------------------
78
+ # function that decrypt information from user
79
+ # -- function gets the encrypted file, private key and return obtained result
80
+ # -- function write result to the file 'decrypted'
81
+ decryptData <- function (fileName , privateKey , passPhrase ) {
82
+ outputDir <- " temp_folder"
83
+ # read file with Encrypted Information (from Computer File System to R Environment)
84
+ secret_encrypted <- read_rds(fileName )
85
+
86
+ # decrypting the list from R Environment
87
+ decrypt_envelope(data = secret_encrypted $ data ,
88
+ iv = secret_encrypted $ iv ,
89
+ session = secret_encrypted $ session ,
90
+ key = privateKey ,
91
+ password = passPhrase ) %> %
92
+ # getting back original object in a form of the data frame
93
+ unserialize() %> %
94
+ # write dataframe to the csv file
95
+ storeData(outputDir , " decrypted.csv" )
96
+
97
+ # remove secret_encrypted object
98
+ rm(secret_encrypted )
99
+ }
100
+
101
+ # --------------------------------------------------------------------
102
+ # function that joins and delete available information to encrypt
103
+ # three souces of information are available:
104
+ # 1. From imported file, 2. from single entry, 3. from decrypted file, 4. previously combined
105
+ joinData <- function (){
106
+ outputDir <- " temp_folder"
107
+ files <- c(" imported.csv" ," singlerow.csv" ," decrypted.csv" )
108
+ # join data from all files and delete original files
109
+ for (i in 1 : 3 ){
110
+ if (file.exists(file.path(outputDir , files [i ]))){
111
+ # store
112
+ if (exists(" df_joined" )){
113
+ df_joined <- df_joined %> %
114
+ bind_rows(read_csv(file.path(outputDir , files [i ])))
115
+ } else {
116
+ df_joined <- read_csv(file.path(outputDir , files [i ]))
117
+ }
118
+ # delete
119
+ file.remove(file.path(outputDir , files [i ]))
120
+ }
121
+
122
+ }
123
+ # return joined dataframe
124
+ saveDataGlobal(df_joined )
125
+ return (df_joined )
126
+
127
+ }
128
+
129
+ # --------------------------------------------------------------------
130
+ # function that encrypt information from user
131
+ # -- function uses the data present in the file and encrypt them using private key
132
+ # -- funciton writes information to the folder
133
+ encryptData <- function (privateKey , passphrase ) {
134
+ outputDir <- " temp_folder"
135
+ # retrieve public key from private one
136
+ pubKey <- read_key(file = privateKey , password = passphrase ) %> %
137
+ # extract element of the list
138
+ `[[`(" pubkey" )
139
+
140
+ # join data collected by user
141
+ joinData() %> %
142
+ # serialize the object
143
+ serialize(connection = NULL ) %> %
144
+ # encrypt the object
145
+ encrypt_envelope(pubKey ) %> %
146
+ # write encrypted data to File
147
+ write_rds(file.path(outputDir , " PasswordList.Encrypted" ))
148
+
149
+ }
150
+
151
+
152
+
153
+
154
+ shinyServer(function (input , output , session ) {
155
+
156
+ # =======================================
157
+ # DEFINE GLOBAL VARIABLES #
158
+ # =======================================
159
+ outputDir <- " temp_folder"
160
+
161
+ # ==================================================
162
+ # Run once in the event of loading file... with Private Key
163
+ observeEvent(input $ inputPK , {
164
+ # Read file
165
+ inFilePK <- input $ inputPK
166
+
167
+ # TDL more secure way is needed (e.g. if wrong file is entered)
168
+ if (is.null(inFilePK ))
169
+ return (NULL )
170
+
171
+ # # store private key into global environment
172
+ # privateKey <- read_key(file = inFilePK$datapath, password = input$passphrase)
173
+
174
+ })
175
+ # ==================================================
176
+ # ==================================================
177
+ # Run once in the event of loading file... with Encrypted Data
178
+ observeEvent(input $ inputEData , {
179
+ # Read file EF -> "Encrypted File"
180
+ inFileEF <- input $ inputEData
181
+
182
+ # TDL more secure way is needed (e.g. if wrong file is entered)
183
+ if (is.null(inFileEF ))
184
+ return (NULL )
185
+
186
+ # store encrypted data to the file 'temp_folder/decrypted.csv'
187
+ decryptData(fileName = inFileEF $ datapath , privateKey = inFilePK $ datapath , passPhrase = input $ passphrase )
188
+
189
+ })
190
+ # ==================================================
191
+
192
+
193
+
194
+
195
+ # ==========================================
196
+ # Objects located in the Tab Add to Encrypt #
197
+ # ==========================================
198
+ # # **-------------- **
199
+ # Object DF will contain the results of the password input. Object can be accessed in the code using DF() notation
200
+ oneRow <- reactive({
201
+ # Data frame
202
+ data.frame (UserName = as.character(input $ txtInputUser ),
203
+ Email = as.character(input $ txtInputEmail ),
204
+ Password = as.character(input $ txtInputPass ),
205
+ Description = input $ txtInputDesc ,
206
+ stringsAsFactors = F )
207
+ })
208
+ # # **-------------- **
209
+
210
+
211
+
212
+ # function that visualizes the current table results if it's stored in GLobal Environment
213
+ viewData <- function () {
214
+ if (exists(" responses" )) {
215
+ responses
216
+ }
217
+ }
218
+
219
+ # Visualize responses in the interactive tables, refresh when some buttons are pressed...
220
+ output $ responses <- renderDataTable({
221
+ # change in reactive inputs below will refresh data
222
+ input $ butSaveRow
223
+ input $ refresh
224
+
225
+ viewData()
226
+ })
227
+ # # *****-------------- *****
228
+
229
+ # # ******-------------- ******
230
+ # show the action button that will enable the data table save to the SQL Database
231
+ # refreshData <- eventReactive(input$refresh, {
232
+ #
233
+ # # code that brings all available decrypted files to very one file
234
+ # # this file will be used for visualizing data in the table
235
+ # #
236
+ # joinData()
237
+ #
238
+ # })
239
+ # # ******-------------- ******
240
+
241
+ # # **-------------- **
242
+ # output to download file of Decrypted Information (secret)
243
+ output $ downloadTable <- downloadHandler(
244
+ filename = function () {
245
+ paste(" Data-" , Sys.Date(), ' .csv' , sep = ' ' )
246
+ },
247
+ content = function (file ) {
248
+ write.csv(df , file )
249
+ }
250
+ )
251
+ # # **-------------- **
252
+
253
+ # ==========================================
254
+ # Objects located in the Tab Key Management #
255
+ # ==========================================
256
+
257
+ # # **-------------- **
258
+ # output to download file with Private Key
259
+ output $ downloadPrvKey <- downloadHandler(
260
+ filename = function () {
261
+ paste(Sys.Date(), input $ keyname , sep = " " )
262
+ },
263
+ content = function (file ) {
264
+ # generate the key
265
+ generatePrivateKey(keyBits = input $ keybits , keyPath = input $ keyname , passphrase = input $ passphrase )
266
+ file.copy(paste(Sys.Date(), input $ keyname , sep = " " ), file )
267
+ }
268
+ )
269
+ # # **-------------- **
270
+ # # **-------------- **
271
+ # output to download file with Public Key
272
+ output $ downloadPubKey <- downloadHandler(
273
+ filename = function () {
274
+ paste(Sys.Date(), input $ keyname , " Pub" , sep = " " )
275
+ },
276
+ content = function (file ) {
277
+ # generate the key
278
+ k <- read_key(file = paste(Sys.Date(), input $ keyname , sep = " " ), password = input $ passphrase )
279
+ write_pem(k $ pubkey , path = paste(Sys.Date(), input $ keyname , " Pub" , sep = " " ))
280
+ file.copy(paste(Sys.Date(), input $ keyname , " Pub" , sep = " " ), file )
281
+ }
282
+ )
283
+ # # **-------------- **
284
+ # # **-------------- **
285
+ # Now user must press the button to delete the key from R Environment
286
+ observeEvent(input $ delKey , {
287
+ # user deletes the key once sure that it's saved
288
+ file.remove(paste(Sys.Date(), input $ keyname , sep = " " ))
289
+ })
290
+
291
+
292
+ # # **-------------- **
293
+
294
+ # # ****-------------- ****
295
+ # get value of the input number that indicate which line to delete
296
+ lineToDelete <- reactive({ lineToDelete <- input $ numLineDelete })
297
+ # pressing button will delete single line inside of the response object
298
+ observeEvent(input $ eraseLine , {
299
+ # delete the first element of the table
300
+ responses <- responses [- lineToDelete(), ]
301
+ })
302
+ # # ****-------------- ****
303
+
304
+ # # ****** ---------------*******
305
+ # Uploading data using the app
306
+ observeEvent(input $ importPassw , {
307
+ pFile <- input $ importPassw
308
+ if (is.null(pFile ))
309
+ return ()
310
+ # TDL: add fail safe (wrong file, etc)
311
+ })
312
+ # # ******---------------********
313
+ # this will bring data from imported file from user
314
+ dataFromImport <- eventReactive(input $ importPassw , {
315
+ # return data from imported file on request
316
+ req(input $ importPassw )
317
+ # save to dataframe
318
+ df_imported <- read_csv(input $ importPassw $ datapath )
319
+ # store this data persistently... (temporary, further on shall be removed)
320
+ storeData(data = df_imported , directoryName = outputDir , fileName = " imported.csv" )
321
+ # join the data we have already
322
+ df_imported <- joinData()
323
+ return (df_imported )
324
+ })
325
+
326
+ # # *****-------------- *****
327
+ # this will bring data stored by user (one line)
328
+ dataFromSingleEntry <- eventReactive(input $ butSaveRow , {
329
+ # save data file to temp directory (temporary, further on shall be removed)
330
+ storeData(data = DF(), directoryName = outputDir , fileName = " singlerow.csv" )
331
+ # join the data we have already
332
+ df_single <- joinData()
333
+ return (df_single )
334
+ })
335
+
336
+ # ## *****-------------- *****
337
+ # # this will bring decrypted data from file
338
+ # dataFromDecryption <- eventReactive(input$butSaveRow, {
339
+ # # save data file to temp directory (temporary, further on shall be removed)
340
+ # saveData(data = DF(), directoryName = outputDir, fileName = "decrypted.csv")
341
+ # # join the data we have already
342
+ # df_decrypted <- joinData()
343
+ # return(df_decrypted)
344
+ # })
345
+ #
346
+ # =================================
347
+ # visualize the table that user loads
348
+ output $ viewPasswords <- renderDataTable({
349
+ # data coming from imported files
350
+ input $ refresh
351
+ input $ butSaveRow
352
+
353
+ joinData()
354
+ })
355
+
356
+ # # ****-------------- ****
357
+ # output the results of the data input as a datatable vector
358
+ output $ viewOneRow <- renderDataTable({ oneRow() })
359
+ # # ****-------------- ****
360
+
361
+
362
+ })
0 commit comments