MCPcopy
hub / github.com/jhaals/yopass / streamDownload

Method streamDownload

pkg/server/server_stream.go:171–244  ·  view source on GitHub ↗

streamDownload serves the encrypted file as a binary stream.

(w http.ResponseWriter, r *http.Request)

Source from the content-addressed store, hash-verified

169
170// streamDownload serves the encrypted file as a binary stream.
171func (y *Server) streamDownload(w http.ResponseWriter, r *http.Request) {
172 w.Header().Set("Cache-Control", "private, no-cache")
173
174 key := mux.Vars(r)["key"]
175 session, sessionErr := y.getSession(r)
176 audit := y.newAuditor("file.downloaded", y.getRealClientIP(r), session)
177 audit.setSecretID(key)
178
179 // Read metadata without consuming it (Status never deletes).
180 secret, err := y.DB.Status(streamKeyPrefix + key)
181 if err != nil {
182 y.Logger.Debug("Stream secret not found", zap.Error(err))
183 audit.failure("not found")
184 jsonError(w, http.StatusNotFound, "Secret not found")
185 return
186 }
187
188 if !y.authorizeSecretAccess(w, secret, session, sessionErr, audit) {
189 return
190 }
191
192 isOneTime := secret.OneTime
193
194 // For one-time secrets: atomically claim ownership by deleting the metadata
195 // key BEFORE loading the file.
196 if isOneTime && !y.claimOneTimeSecret(w, streamKeyPrefix+key, audit) {
197 return
198 }
199
200 // Load file from store
201 ctx := r.Context()
202 reader, size, err := y.FileStore.Load(ctx, key)
203 if err != nil {
204 y.Logger.Error("Failed to load streaming file", zap.Error(err))
205 // DB metadata exists but the file is gone — clean up the stale DB entry.
206 if !isOneTime {
207 if _, delErr := y.DB.Delete(streamKeyPrefix + key); delErr != nil {
208 y.Logger.Error("Failed to clean up stale stream metadata", zap.Error(delErr))
209 }
210 }
211 audit.failure("file not found in store")
212 jsonError(w, http.StatusNotFound, "File not found")
213 return
214 }
215 defer reader.Close()
216
217 // Set response headers
218 w.Header().Set("Content-Type", "application/octet-stream")
219 w.Header().Set("Access-Control-Expose-Headers", "Content-Length")
220 if size > 0 {
221 w.Header().Set("Content-Length", strconv.FormatInt(size, 10))
222 }
223
224 // Stream the file
225 if _, err := io.Copy(w, reader); err != nil {
226 y.Logger.Error("Failed to stream file", zap.Error(err))
227 return
228 }

Callers 1

Calls 15

getSessionMethod · 0.95
newAuditorMethod · 0.95
getRealClientIPMethod · 0.95
authorizeSecretAccessMethod · 0.95
claimOneTimeSecretMethod · 0.95
markReceiptViewedMethod · 0.95
webhookViewedMethod · 0.95
jsonErrorFunction · 0.85
withOneTimeFunction · 0.85
withRequireAuthFunction · 0.85
setSecretIDMethod · 0.80
failureMethod · 0.80

Tested by 1