9
9
"encoding/csv"
10
10
"encoding/json"
11
11
"fmt"
12
+ "io"
12
13
"os"
13
14
"path/filepath"
14
15
"strings"
@@ -25,16 +26,19 @@ import (
25
26
26
27
// Acquisition is the main object containing all phone information
27
28
type Acquisition struct {
28
- UUID string `json:"uuid"`
29
- AndroidQFVersion string `json:"androidqf_version"`
30
- StoragePath string `json:"storage_path"`
31
- Started time.Time `json:"started"`
32
- Completed time.Time `json:"completed"`
33
- Collector * adb.Collector `json:"collector"`
34
- TmpDir string `json:"tmp_dir"`
35
- SdCard string `json:"sdcard"`
36
- Cpu string `json:"cpu"`
37
- closeLog func () `json:"-"`
29
+ UUID string `json:"uuid"`
30
+ AndroidQFVersion string `json:"androidqf_version"`
31
+ StoragePath string `json:"storage_path"`
32
+ Started time.Time `json:"started"`
33
+ Completed time.Time `json:"completed"`
34
+ Collector * adb.Collector `json:"collector"`
35
+ TmpDir string `json:"tmp_dir"`
36
+ SdCard string `json:"sdcard"`
37
+ Cpu string `json:"cpu"`
38
+ closeLog func () `json:"-"`
39
+ EncryptedWriter * EncryptedZipWriter `json:"-"`
40
+ StreamingMode bool `json:"streaming_mode"`
41
+ StreamingPuller * StreamingPuller `json:"-"`
38
42
}
39
43
40
44
// New returns a new Acquisition instance.
@@ -76,25 +80,70 @@ func New(path string) (*Acquisition, error) {
76
80
}
77
81
acq .Collector = coll
78
82
79
- // Init logging file
80
- logPath := filepath .Join (acq .StoragePath , "command.log" )
81
- closeLog , err := log .EnableFileLog (log .DEBUG , logPath )
83
+ // Try to initialize encrypted streaming mode
84
+ encWriter , err := NewEncryptedZipWriter (acq .UUID )
82
85
if err != nil {
83
- return nil , fmt .Errorf ("failed to enable file logging: %v" , err )
84
- }
86
+ // No key file or encryption setup failed, use normal mode
87
+ log .Debug ("Encrypted streaming not available, using normal mode" )
88
+ acq .StreamingMode = false
85
89
86
- // Store cleanup function for later use
87
- acq .closeLog = closeLog
90
+ // Init logging file for normal mode
91
+ logPath := filepath .Join (acq .StoragePath , "command.log" )
92
+ closeLog , err := log .EnableFileLog (log .DEBUG , logPath )
93
+ if err != nil {
94
+ return nil , fmt .Errorf ("failed to enable file logging: %v" , err )
95
+ }
96
+ acq .closeLog = closeLog
97
+ } else {
98
+ // Encrypted streaming mode enabled
99
+ log .Info ("Using encrypted streaming mode - data will be written directly to encrypted archive" )
100
+ acq .StreamingMode = true
101
+ acq .EncryptedWriter = encWriter
102
+ acq .closeLog = nil // No separate log file in streaming mode
103
+
104
+ // Initialize streaming puller for direct operations
105
+ acq .StreamingPuller = NewStreamingPuller (adb .Client .ExePath , 100 ) // 100MB max memory
106
+ }
88
107
89
108
return & acq , nil
90
109
}
91
110
92
111
func (a * Acquisition ) Complete () {
93
112
a .Completed = time .Now ().UTC ()
94
113
95
- // Ensure log file is closed before cleanup operations
96
- if a .closeLog != nil {
97
- defer a .closeLog ()
114
+ // Handle streaming mode completion
115
+ if a .StreamingMode && a .EncryptedWriter != nil {
116
+ // Store acquisition info in the encrypted zip
117
+ info , err := json .MarshalIndent (a , "" , " " )
118
+ if err != nil {
119
+ log .Error ("Failed to marshal acquisition info for encrypted archive" )
120
+ } else {
121
+ err = a .EncryptedWriter .CreateFileFromBytes ("acquisition.json" , info )
122
+ if err != nil {
123
+ log .ErrorExc ("Failed to store acquisition info in encrypted archive" , err )
124
+ }
125
+ }
126
+
127
+ // Close the encrypted writer
128
+ err = a .EncryptedWriter .Close ()
129
+ if err != nil {
130
+ log .ErrorExc ("Failed to close encrypted archive" , err )
131
+ }
132
+
133
+ // Remove the temporary storage directory if it was created and used
134
+ if a .StoragePath != "" {
135
+ if _ , err := os .Stat (a .StoragePath ); err == nil {
136
+ err = os .RemoveAll (a .StoragePath )
137
+ if err != nil {
138
+ log .ErrorExc ("Failed to clean up temporary storage directory" , err )
139
+ }
140
+ }
141
+ }
142
+ } else {
143
+ // Ensure log file is closed before cleanup operations
144
+ if a .closeLog != nil {
145
+ defer a .closeLog ()
146
+ }
98
147
}
99
148
100
149
if a .Collector != nil {
@@ -144,6 +193,12 @@ func (a *Acquisition) GetSystemInformation() error {
144
193
}
145
194
146
195
func (a * Acquisition ) HashFiles () error {
196
+ // In streaming mode, files are directly encrypted and no local files exist to hash
197
+ if a .StreamingMode {
198
+ log .Debug ("Skipping hash generation in streaming mode (data is encrypted)" )
199
+ return nil
200
+ }
201
+
147
202
log .Info ("Generating list of files hashes..." )
148
203
149
204
csvFile , err := os .Create (filepath .Join (a .StoragePath , "hashes.csv" ))
@@ -183,6 +238,11 @@ func (a *Acquisition) HashFiles() error {
183
238
}
184
239
185
240
func (a * Acquisition ) StoreInfo () error {
241
+ // In streaming mode, info is stored during Complete()
242
+ if a .StreamingMode {
243
+ return nil
244
+ }
245
+
186
246
log .Info ("Saving details about acquisition and device..." )
187
247
188
248
info , err := json .MarshalIndent (a , "" , " " )
@@ -201,3 +261,74 @@ func (a *Acquisition) StoreInfo() error {
201
261
202
262
return nil
203
263
}
264
+
265
+ // StreamAPKToZip streams an APK file directly to encrypted zip with certificate processing
266
+ func (a * Acquisition ) StreamAPKToZip (remotePath , zipPath string , processFunc func (io.Reader ) error ) error {
267
+ if ! a .StreamingMode || a .EncryptedWriter == nil {
268
+ return fmt .Errorf ("streaming mode not available" )
269
+ }
270
+
271
+ // Pull APK data to memory buffer
272
+ buffer , err := a .StreamingPuller .PullToBuffer (remotePath )
273
+ if err != nil {
274
+ return fmt .Errorf ("failed to pull APK %s: %v" , remotePath , err )
275
+ }
276
+
277
+ // Process APK if processor provided (e.g., certificate verification)
278
+ if processFunc != nil {
279
+ err = processFunc (buffer .Reader ())
280
+ if err != nil {
281
+ return fmt .Errorf ("failed to process APK %s: %v" , remotePath , err )
282
+ }
283
+ }
284
+
285
+ // Stream to encrypted zip
286
+ err = a .EncryptedWriter .CreateFileFromReader (zipPath , buffer .Reader ())
287
+ if err != nil {
288
+ return fmt .Errorf ("failed to add APK %s to encrypted zip: %v" , remotePath , err )
289
+ }
290
+
291
+ return nil
292
+ }
293
+
294
+ // StreamBackupToZip streams a backup directly to encrypted zip
295
+ func (a * Acquisition ) StreamBackupToZip (arg , zipPath string ) error {
296
+ if ! a .StreamingMode || a .EncryptedWriter == nil {
297
+ return fmt .Errorf ("streaming mode not available" )
298
+ }
299
+
300
+ // Create zip entry writer
301
+ writer , err := a .EncryptedWriter .CreateFile (zipPath )
302
+ if err != nil {
303
+ return fmt .Errorf ("failed to create zip entry for backup: %v" , err )
304
+ }
305
+
306
+ // Stream backup directly to zip
307
+ err = a .StreamingPuller .BackupToWriter (arg , writer )
308
+ if err != nil {
309
+ return fmt .Errorf ("failed to stream backup to zip: %v" , err )
310
+ }
311
+
312
+ return nil
313
+ }
314
+
315
+ // StreamBugreportToZip streams a bugreport directly to encrypted zip
316
+ func (a * Acquisition ) StreamBugreportToZip (zipPath string ) error {
317
+ if ! a .StreamingMode || a .EncryptedWriter == nil {
318
+ return fmt .Errorf ("streaming mode not available" )
319
+ }
320
+
321
+ // Create zip entry writer
322
+ writer , err := a .EncryptedWriter .CreateFile (zipPath )
323
+ if err != nil {
324
+ return fmt .Errorf ("failed to create zip entry for bugreport: %v" , err )
325
+ }
326
+
327
+ // Stream bugreport directly to zip
328
+ err = a .StreamingPuller .BugreportToWriter (writer )
329
+ if err != nil {
330
+ return fmt .Errorf ("failed to stream bugreport to zip: %v" , err )
331
+ }
332
+
333
+ return nil
334
+ }
0 commit comments