Summary#
A private upload — Upload(privately: true) on a page, a paste or a drop — lands at a path the platform chooses under
uploads/, and that path records who made it. The page then hands the path to one of your functions. Before that
function keeps the file as the caller's own, it asks:
if (!File.IsOwnUpload(upload.Path)) { throw new ValidationException("Please upload the file again."); }true means the caller uploaded it — the same signed-in person, or, signed out, the same browser. Anybody else holding
the path — a log line, a shared screen, another tab signed in as somebody else — gets false.
Signature#
bool File.IsOwnUpload(string path) // did the CALLER upload this private upload?
string File.SaveUpload(string fileName, byte[] bytes) // store bytes as the caller's private upload; answers its pathDescription#
Needs use Osysharp.Storage;.
- Who "the caller" is. The signed-in account, or the visit the platform issued the browser when nobody is signed in. Both are tried, so somebody who pasted a screenshot signed out and then signed in is still its uploader. Neither is an argument: you cannot ask on somebody else's behalf.
- What answers
false. Any path the platform did not choose for a private upload (public/…, a path your own code wrote withFile.WriteAllBytes), and any upload made by somebody else. File.SaveUploadkeeps the file name's extension and nothing else of it. It is refused when there is nobody to record — a background run with no caller writes bytes withFile.WriteAllBytesinstead. In a test it is how a test stands in for the page's upload:runasthe person, save, and hand the path to the function under test.- Uploads are limited. One browser (or one signed-in person) may upload 30 files a minute and 200 MB an hour to an
app, and one network address 300 files a minute. Past that the upload is refused with
429and the sentence "Too many files have been uploaded from here in a short time. Wait … and try again.", and nothing is stored. These are the defaults; whoever runs the platform sets its own numbers underPlatform:Uploads(UploadsPerCallerPerMinute,MegabytesPerCallerPerHour,UploadsPerAddressPerMinute).
Examples#
app Desk { use Osysharp.Storage; }
using Osysharp.Storage;
[AllowAnonymous]
public Guid Keep(UploadedFile upload) {
if (!File.IsOwnUpload(upload.Path)) {
throw new ValidationException("That file was uploaded somewhere else. Please upload it again.");
}
var file = File.Create(upload.FileName, upload.ContentType, File.ReadAllBytes(upload.Path));
File.Delete(upload.Path);
return file.Id;
}[Test]
void An_upload_is_its_uploaders() {
var path = "";
runas (new Visitor { Id = "visit-a" }) { path = File.SaveUpload("shot.png", [137, 80, 78, 71]); }
runas (new Visitor { Id = "visit-b" }) { Assert.False(File.IsOwnUpload(path)); }
runas (new Visitor { Id = "visit-a" }) { Assert.True(File.IsOwnUpload(path)); }
}See also#
- upload — the
Uploadatom, andprivately: true - Files (addressing something the app stores) — the two ways the platform stores a file
- File.SignedUrl — how a private file is shown