Downloading images from publicly shared folder on Dropbox - c#

I received a link to shared folder from e-commerce company. The link is public and not shared with my dropbox account directly.
How do I get an url to the image that I can pass to either DownloadAsync method of the same sdk or simply HttpClient and well ... download it?
Ideally it would be the same link I get when I click on the image when viewing that shared folder in a browser.
https://www.dropbox.com/sh/{folder_hash}/{file_hash_maybe}/{filename}?dl=0
This is what I have tried:
using Dropbox.Api;
using Dropbox.Api.Files;
...
var accessToken = "abracadabra";
var sharedFolderUrl = "https://www.dropbox.com/sh/{folder_hash}?dl=0";
using (var dbx = new DropboxClient(accessToken))
{
var sharedLink = new SharedLink(sharedFolderUrl);
var sharedFiles = await dbx.Files.ListFolderAsync(path: "", sharedLink: sharedLink);
// sharedFiles - has over 13,000 entries, I use cursor to get them all.
foreach (var file in sharedFiles.Entries)
{
if (file.IsFile)
{
// tried this, but:
// 1. it's crazy to loop through all
// 2. link.Response.Url gives me the same url to a shared folder for all items
var link = await dbx.Sharing.GetSharedLinkFileAsync(url: sharedFolderUrl, path: "/" + file.Name);
}
}
}

Using the GetSharedLinkFileAsync method is the right way to programmatically download a file from a shared link. It actually gives both the metadata (in the link.Response in your code like you mentioned), as well as the file data directly (not via a URL).
To access the file data, you can use any of the GetContentAs... methods documented under IDownloadResponse as returned by GetSharedLinkFileAsync. In your code, that would look something like: link.GetContentAsStreamAsync() (or whichever one you want).
Alternatively, if you want to download the entire folder from the shared link, you can use the URL parameters documented in this help center article. (That may fail for very large folders though.)

Related

c# - Physical path given, virtual path expected in Server.MapPath

I trying to change my directory which in my local c disk, but where errors says in the title. Is there any way aside from using Server.MapPath?. I'm using a ZipOutputStream nuget package.
I want to locate my directory in C: instead inside the project folder.
public FileResult DownloadZipFileSig(string FileId){
var fileName = "FilesDL".zip";
var tempOutPutPath = Server.MapPath(Url.Content("C:/Users/SDILAP2/Desktop/ID_Esig_Files")) + fileName;
using (ZipOutputStream s = new ZipOutputStream(System.IO.File.Create(tempOutPutPath)))
{
s.SetLevel(9);
byte[] buffer = new byte[4096];
List<string> stringList = FileId.Split(',').ToList();
List<string> tempList = new List<string>();
foreach (string str in stringList)
{
if (System.IO.File.Exists(Server.MapPath("C:/Users/SDILAP2/Desktop/ID_Esig_Files/" + str + ".jpeg")))
{
tempList.Add(Server.MapPath("C:/Users/SDILAP2/Desktop/ID_Esig_Files/" + str + ".jpeg"));
}
}
stringList = tempList;
for (int i = 0; i < stringList.Count; i++)
{
ZipEntry entry = new ZipEntry(Path.GetFileName(stringList[i]));
entry.DateTime = DateTime.Now;
entry.IsUnicodeText = true;
s.PutNextEntry(entry);
using (FileStream fs = System.IO.File.OpenRead(stringList[i]))
{
int sourceBytes;
do
{
sourceBytes = fs.Read(buffer, 0, buffer.Length);
s.Write(buffer, 0, sourceBytes);
} while (sourceBytes > 0);
}
}
s.Finish();
s.Flush();
s.Close();
}
return File(finalResult, "application/zip", fileName);
}
You might be not quite grasping how web URL's work, and how server.mappath() is to be used.
Web users:
When you have a web based url, then all html markup in a page, or even user supplied URL's are so called web based.
So, if you have a folder from the root of your web site say called MyUpLoads
Then that is just a folder in the web site path names.
eg:
www.mywebsite/UpLoadFiles/cat.jpg
And if you write html markup, then you can and could provide a URL to the above picute, or say with a html image control, you could set the ImageURL or "source" (src) to that file.
And if you using IIS (and not IIS express), then of course you can add what is called a virutal folder. Say some big server drive on ANOHTER computer on the same network.
So, that virtual folder could be anywhere on your network, and of course AGAIN for web HTML, or web URL's, again you use this format:
www.mysite/MassiveFolder/info.pdf
or maybe
localhost:5403/MyUpLoads/cat.jpg
However, in code behind?
ANY code behind (c# or vb.net) ALWAYS uses plane jane WINDOWS file paths.
These are valid full windows file names.
That means that code behind is 100% free to open/read/use/see/play with ANY file on the computer, and any file even on the computer network.
So when you use
server.mapPath("localhost:5403/MyUpLoads/cat.jpg")
Then the above is translated into a local plane jane DOS/WINDOWS file path!!!!
The above may well become
C:\Users\AlbertKallal\source\repos\CSharpWebApp\MyUpLoads\cat.jpg
So keep in mind:
web urls - HTML/asp markup in a page = web based syntax/path.
computer path: plane jane full path names like all windows software.
So, in your case?
var fileName = "FilesDL".zip";
var tempOutPutPath = #"C:/Users/SDILAP2/Desktop/ID_Esig_Files")) + fileName;
So you don't need nor want to user server.mappath, since that is ONLY for a given HTML or web based URL that you want to translate into the local computer file path system.
Since your path name(s) are already in that format, then no need is required.
in fact, keep in mind that you can use this fact to your advantage.
ANY folder (or a vitural folder) will appear in your valid URL's and path names (web based).
However, you might have some pdf's, or sensitive documents. So move that folder OUT of the root or web project folders.
Now, no valid URL's exist, or are even allowed.
However, code behind? It can run, see and use ANY file on your computer - and you use code behind to get those files - but the web site, web side of things has NO ability to use or see or get those files. And you can still do things like say provide a download button, but your code behind can fetch the file, read it and pump it out to the end user (stream the file).
So you only need (have) to use the Server.MapPath function WHEN the URL comes from the web site or html markup. This will translate that web based URL into a regular good old fashion full qualified windows file path name.
However, if you already have that full windows path name, then no URL translate to windows file path is required.
So, for the most part, your code behind can look at, see, grab and play with files on the server. Web users, or web based urls MUST be part of the folders in the web site, but no such restrictions exist for the code behind.
Now, when the code is deployed to a web server, often some file security rights on in place, but as a general rule, that web code behind is NOT limited nor restricted to JUST folders in the web site. Those valued URL's are a restriction for the users and web browsers, and as noted, often a folder outside of the web site is used for security purposes, since no possible valid web based paths can use/see or even resolve to file outside of the root starting folder of the web site.
So for those existing files, you don't need server.mappath.

Why can't I access static files that I add programmatically from a POST request?

I'm attempting to make a basic .NET API for managing a collection of media (images and videos).
I have configured the webroot to be a folder called "site", and within that folder is a folder called "media" where these files are stored. I can access a test media file that is saved in /site/media/Smush.jpg by loading https://localhost:5001/site/media/smush.jpg - this serves the image as expected.
I have created a method that receives a POST request containing form data from my frontend, and this method saves the file to the webroot using a filestream, code below:
[HttpPost]
[Route("/media/add")]
public async Task<HttpResponseMessage> MediaAdd()
{
try
{
//get the form
var form = HttpContext.Request.Form;
//if there's a route, add it into the filepath, otherwise leave it out and have the filepath go straight to media (this prevents an exception if route is blank)
string filePath = form["route"] == "" ? Path.Combine(_hostingEnvironment.WebRootPath, "media") : Path.Combine(_hostingEnvironment.WebRootPath, "media", form["route"]);
//get the first (should be only) image - DO WE WANT TO BE ABLE TO ADD MULTIPLE IMAGES? PROBABLY TBH
IFormFile image = form.Files.First();
if (image.Length > 0)
{
//check the directory exists - create it if not
if (!Directory.Exists(filePath)) {
Directory.CreateDirectory(filePath);
}
using (Stream fileStream = new FileStream(Path.Combine(filePath, form["filename"]), FileMode.Create))
{
await image.CopyToAsync(fileStream);
return new HttpResponseMessage(HttpStatusCode.OK);
}
}
else {
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
}
catch (Exception e)
{
return new HttpResponseMessage(HttpStatusCode.BadRequest);
}
}
My frontend submits a route, filename and the media file, and this is used to save the image. This all works fine; I can submit an image with the path "test" and the name "test.jpg", and the API correctly stores the file at /site/media/test/test.jpg. I can view the file in the solution and see a preview of the image, as with Smush.jpg.
However, attempting to load https://localhost:5001/site/media/test/test.jpg results in a 404. Why is this the case? Can I not add files into the webroot through code and have them be accessible as static files as if I added them to the solution in my IDE? Are there any alternative ways of handling this?
I am using .NET 5.0, and have
app.UseStaticFiles(); in Configure() in Startup.cs.
Sorry if this is a duplicate, but I couldn't find anything else like this.
EDIT:
On checking things again, it seems like rather than my files being at https://localhost:5001/site/media, they are simply in https://localhost:5001/media. I am not sure how I was able to access Smush.jpg at https://localhost:5001/site/media/Smush.jpg before.
It seems as though the webroot is not included as part of a URL to access files within it.
As it is now, I have got what I was looking for it to do.
Well first a security concern as also #Heinzi pointed out...
string filePath = form["route"] == "" ? Path.Combine(_hostingEnvironment.WebRootPath, "media") : Path.Combine(_hostingEnvironment.WebRootPath, "media", form["route"]);
What if the user sends form.route == "../../" and instead of image he updates the appsettings.json file ?
Check this out and have that in mind if you're planing to release this code to a production environment and make sure you only accept image files.
On the other hand if you are serving static files from a folder different to wwwroot please use this configuration
Why the 404
It makes sense. You are under the controller/action paths. Going under the site url the engine does the following:
When you request https://localhost:5001/site/media/test/test.jpg the code tries to find the media controller and the test action. It is not looking for static files on the filesystem. Since there is no such controller/action pairs, it will not find anything and thus return 404 not found.
If you saved the files in https://localhost:5001/static/media/test.jpg outside of the mapped routes, you would be able to access it.
Look inside your code for:
MapHttpRoute
Which is used to configure how to identify controller actions which are not decorated with the [Route] attribute.
Security concern
When you want to upload a file, you should consider a better solution and not one that accesses directly your filesystem.
Possible options:
Blob storage on the cloud
Database blobs
Don't forget to sanitize the input with an antivirs or some similar solution.

How to GetFileReference to an Azure blob/file if I have the _full_ absolute uri?

In my database I have the full absolute Uri to our azure files.
eg.
https://<snip>.file.core.windows.net/share1/Brand1/Export_2017-05-11-12-54.xml
https://<snip>.file.core.windows.net/share1/Brand1/asdfasdfasd.xml
https://<snip>.file.core.windows.net/share1/Brand2/PewPew%20-%20Sample-78206580-1dd8-4de2-9b92-002bdca861a5.xml
Please note:
Azure files Share name e.g. share1
The file names have one ore more / in em. e.g. brand1/blah.xml
I'm trying to see if the file exists and then do stuff with it (e.g. download it, whatever).
I need to get a File Reference to this item first. I've done all the ceremony to set that up (SAS, etc).
This is how I get a file reference to a file:
var cloudFile = ShareRootDirectory.GetFileReference(fileName);
if the fileName = "Brand1/Export_2017-05-11-12-54.xml it would work (note: no share or https://.... there.)
otherwise I get an error.
Is there some way, given a full absolute uri to a file on azure, can I pass something to my previously setup ShreRootDirectory to get/check the file? Or do I need to do it another way?
Is there some trick?
Note:
- I have a share folder (for files)
- Filenames have / in them which gives the illusion of folders.
Here's a screen shot of me doing this:
var tempCloudFile = new CloudFile(new Uri(fileName));
If you have access to storage credentials, you can use the following override of CloudFile to get a reference for that file and then perform operations on that file. For example, I get a reference for CloudFile below and checking for its existence.
var cred = new StorageCredentials(accountName, accountKey);
var file = new CloudFile(new Uri("https://<snip>.file.core.windows.net/share1/Brand1/Export_2017-05-11-12-54.xml"), cred);
var exists = file.Exists();

How to retrieve shared link using Dropbox.Api v 2.0 client nuget library in C#?

I've been working with this for hours, I have .png files inside Dropbox and I need to get a raw link to those files so I can use it within my code. How can I retrieve in C# a shared link that I have in Dropbox? I need to retrieve that link so I can use it in my view to assign it to a src parameter for an image. Inside my controller I'm using the CreateSharedLinkWithSettingsArg method which creates shared links for files, but how can I get those links after? This is my code:
List<Dropbox.Api.Files.Metadata> list = new List<Dropbox.Api.Files.Metadata>();
foreach (var item in list)
{
var path = new Dropbox.Api.Sharing.CreateSharedLinkWithSettingsArg(item.PathDisplay);
}
I've used something like this and works good but this code throws an exception when the shared link already exists because the following code tries to create a shared link always, I've shared all the files and I just need to get the shared link within my code, how can I do this?:
var sharing = await client.Sharing.CreateSharedLinkWithSettingsAsync(path);
var src = sharing.Url;
I'm using Dropbox.Api v 2.0 and C#

How to download files from OneDrive

I am looking to download my files in public folder from One Drive, but it doesn't download the files.
Here is the scenario:
In public folder I have another folder with multiple files in it and is accessible widely.
for test purpose I have shared all the files in public folder (I don't if it's proper way of sharing it).
The following links are provided for me to download the file:
From shared folder link https://onedrive.live.com/redir?resid=DBBC281099F4FE69!646&authkey=!AGRCGuw8Y2_p9mA&ithint=folder%2c.mp3
From public folder link https://onedrive.live.com/redir?resid=DBBC281099F4FE69%21646
Direct link http://1drv.ms/1z9XlW6 -
I am using BackgroundTransferRequest to download the file using below code:
string filePathToDownload = string.Empty, fileName = "111.mp3";
filePathToDownload = "http://1drv.ms/1z9XlW6";
Uri transferUri = new Uri(Uri.EscapeUriString(filePathToDownload), UriKind.RelativeOrAbsolute);
BackgroundTransferRequest transferRequest = new BackgroundTransferRequest(transferUri);
transferRequest.Method = "GET";
transferRequest.TransferPreferences = TransferPreferences.AllowCellularAndBattery;
Uri downloadUri = new Uri(DataSource.TEMPDOWNLOADLOCATION + fileName, UriKind.RelativeOrAbsolute);
transferRequest.DownloadLocation = downloadUri;
transferRequest.Tag = fileName;
The file is 300Kb, but this only downloads 6 Kb.
How can I directly download the file from the links above (any of them)?
thanks!
If you replace the word redir with download in the url you get the raw file instead of the webpage i.e.
https://onedrive.live.com/download?resid=DBBC281099F4FE69%21646
Basically, you can't. Those links are links to the web content that shows the files you have shared. If your scenario doesn't mind asking the user to log in to OneDrive, then you can use the Live SDK to access these files.
To access your public folder from Live SDK, you need to either use Live SDK to get the folder-id for your public folder, or convert the IDs in the URL you copied into the format the Live SDK uses:
folder.<user-id>.<folder-resid>
Where is the part of before the !. In general you shouldn't construct an ID, since it's possible the IDs will change in the future, and instead you should retrieve the ID from the service. However, with the URL you pasted the ID would be:
folder.DBBC281099F4FE69.DBBC281099F4FE69!646
Which will allow you to call
https://apis.live.net:443/v5.0/folder.DBBC281099F4FE69.DBBC281099F4FE69!646/files?access_token=<valid_token>
and retrieve the IDs for the individual files, which you can then download via Live SDK following these details: http://msdn.microsoft.com/en-US/library/dn659726.aspx#download_a_file
For those who are still looking for a response to that question.
The easiest way to find the file path is to go to One Drive on the web and right-click on the file that we want and select Embed. Ξ€hen on the right we see the info window to integrate our file into a page. Inside the iframe is the source of the file. Then we have to replace the word embed with the word download and that's it.
Try something like this
//we first need the file id
string id = string.Empty;
//we need to get all of the filenames stored in the root of the skydrive account
LiveOperationResult result = await this.client.GetAsync("me/skydrive/files");
//lets make a list of all these filenames
List<object> items = result.Result["data"] as List<object>;
//for every filename, check if it is what we want, in this case "sample.txt"
//if it is what we want, get the id and save it to out already defined id value
foreach (object item in items)
{
IDictionary<string, object> file = item as IDictionary<string, object>;
if (file["name"].ToString() == "sample.txt")
{
id = file["id"].ToString();
}
}
//to download the file we need to use the id + "/content"
LiveDownloadOperationResult result2 = await client.DownloadAsync(string.Format("{0}/content", id));
//once the file had downloaded, lets copy it to IsolatedStorage
Stream stream = result2.Stream;
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream fileToSave = storage.OpenFile("sample.txt", FileMode.Create, FileAccess.ReadWrite))
{
stream.CopyTo(fileToSave);
stream.Flush();
stream.Close();
}
}
here client is the object of LiveConnectClient class.
Import
using Microsoft.Live;
using Microsoft.Live.Controls;
Here is use txt file as an example. Go through this example:http://www.baileystein.com/2013/10/20/skydrive-how-to-upload-and-download-a-text-file-on-wp8/

Categories

Resources