My (non-sandboxed) app has an embedded XPC helper which runs as root.
I would like to reference the (real) user's home directory from inside my helper, but these usual suspects simply return /var/root:
FileManager.default.homeDirectoryForCurrentUser
NSHomeDirectory()
I can't simply pass Users/bob to my helper for security reasons — if an exploit managed to call my helper method with any URL it wished, and my helper did things based on that as root, I fear bad things could be achieved.
As vadian commented there are fundamental conceptual issues with what you're asking. What you probably actually want to do is be sure the process communicating with your helper tool is in fact trusted.
To do that you need to use SecCodeCreateWithXPCMessage and then use the resulting SecCode instance to validate the caller. For an example of how to do that, take a look at the acceptMessage function in the SecureXPC framework.
EDIT: Turns out there is a way to do this that does work from a Command Line Tool such as one installed with SMJobBless. This answer is adapted from Apple's Technical Q&A QA1133.
If you for whatever reason want to ignore the above, there's an approach you can take which may produce unexpected results if multiple users have active consoles. From Apple's documentation for SCDynamicStoreCopyConsoleUser: "Note that this function only provides information about the primary console. It does not provide any details about console sessions that have fast user switched out or about other consoles."
import SystemConfiguration
extension FileManager {
var homeDirectoryForConsoleUser: URL? {
var homeDirectory: URL?
if let consoleUser = SCDynamicStoreCopyConsoleUser(nil, nil, nil) as String?,
consoleUser != "loginwindow" {
homeDirectory = URL(fileURLWithPath: "/Users/\(consoleUser)")
}
return homeDirectory
}
}
And then you can make use of this anywhere in your helper tool:
if let homeDirectory = FileManager.default.homeDirectoryForConsoleUser {
// Do something useful here
}
Related
I was looking at the documentation for contentsOfDirectory(at:includingPropertiesForKeys:options:)
Particularly I've been focusing on the argument includingPropertiesForKeys, which said:
An array of keys that identify the file properties that you want pre-fetched for each item in the directory. For each returned URL, the specified properties are fetched and cached in the NSURL object. For a list of keys you can specify, see Common File System Resource Keys.
Clicking on URLResourceKey led me to the Apple Documentation about it.
And I was wondering, if I passed in keys like fileResourceTypeKey, fileResourceIdentifierKey, and creationDateKey how could I access those in the returned URL list (after calling contentsOfDirectory(at:includingPropertiesForKeys:options:))?
And I was also confused by the URLResourceKey enum b/c a lot of types have similar descriptions and names to other keys like:
documentIdentifierKey vs fileResourceIdentifierKeyvs localizedNameKey vs nameKey
localizedTypeDescriptionKey vs fileResourceTypeKey vs typeIdentifierKey
the urls returned by the contentsOfDirectory(at:includingPropertiesForKeys:options:) vs pathKey
Like what would be the differences between these keys?
Basically I have a really low understanding of the file system at this point so please bear with my "simple" questions. If someone could explain what all these keys means and how I can access/use them that would be great!
First of all the URLResourceKey documentation describes the kind of the attribute information very well. For example nameKey returns always Desktop for an URL representing ~/Desktop while localizedNameKey returns the localized name Schreibtisch on a German system or Bureau on a French system. However documentIdentifierKey and fileResourceIdentifierKey are completely different attributes.
Regarding the contentsOfDirectory(at:includingPropertiesForKeys:options:) API: The keys passed in the includingPropertiesForKeys parameter tells the framework to pre-fetch the corresponding attributes while getting the contents for performance reasons. For example
let contentURLs = try fileManager.contentsOfDirectory(at: anURL, includingPropertiesForKeys: [.nameKey, .fileSizeKey], options: .skipsHiddenFiles)
To read the attributes call resourceValues(forKeys on the URL passing the same keys as in contentsOfDirectory. Then get the value with the corresponding property of the resource key. The benefit of the combination URLResourceKey / URLResourceValues is you get always the proper type from the file attributes. This avoids any type casting.
for fileURL in contentURLs {
do {
let fileAttributes = try fileURL.resourceValues(forKeys:[.nameKey, .fileSizeKey])
print(fileAttributes.name!) // is String
print(fileAttributes.fileSize!) // is Int
} catch { print(error, fileURL) }
}
I want to use chrome.fileSystem API to create a new file in C:/ or anywhere, but I cannot figure out how to use this API.
I cannot find any argument for file path, only thing is fileEntry, but how can I generate fileEntry with something like C://a/b/c?
Chrome apps have limitations - for security reasons - on what files can be accessed. Basically, the user needs to approve access from your app to the files and directories that are accessed.
The only way to get access to files outside of the app's sandbox is through a user gesture - that is, you need to ask the user for a file. You do this with chrome.fileSystem.chooseEntry.
If this isn't clear of obvious, maybe you could explain more about what you are trying to do with the files and we can give advice on the best way to do this. Usually chrome.fileSystem is not the best choice for data storage - there are other more convenient and sandboxed alterntives like chrome.storage.
It's a bit tricky to work with. But it follows the same model other languages use, except it's even tricker because of all the callbacks. This is a function I wrote to get a nested file entry, creating directories as it goes along. Maybe this can help you get started.
For this function, youd pass in a FileSystem that you'd get from something like chrome.fileSystem.chooseEntry with a directory type option, and path would be in your example ['a','b','c']
function recursiveGetEntry(filesystem, path, callback) {
function recurse(e) {
if (path.length == 0) {
if (e.isFile) {
callback(e)
} else {
callback({error:'file exists'})
}
} else if (e.isDirectory) {
if (path.length > 1) {
e.getDirectory(path.shift(), {create:true}, recurse, recurse)
} else {
e.getFile(path.shift(), {create:true}, recurse, recurse)
}
} else {
callback({error:'file exists'})
}
}
recurse(filesystem)
}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 3 years ago.
Improve this question
I would like to use d to create a RESTful web application.
What are the most actively maintained and contributed projects that are worth considering? A short comparison of these web frameworks with pluses and minuses will be nice.
My search lead me to only one project, which seems like an excellent framework:
vibe.d
Are there other projects which are minimal in nature like sinatra?
I've heard good things about vibe.d http://vibed.org/
Though, I've never personally used it because I wrote my own libraries well before vibe came out.
https://github.com/adamdruppe/misc-stuff-including-D-programming-language-web-stuff
vibe is better documented, so you might be better off going there, but here's how my libraries work:
cgi.d is the base web interface (use -version=embedded_httpd when compiling to use its own web server instead of CGI if you want), and I offer some RESTy stuff in a separate file called web.d. It depends on cgi.d, dom.d, characterencodings.d, and sha.d. You might also want database.d and mysql.d for connecting to a mysql database.
The way web.d works is you just write functions and it automatically maps them to url and formats data.
http://arsdnet.net/cgi-bin/apidemo/add-some-numbers
The source code to that portion is:
import arsd.web;
class MySite : ApiProvider {
export int addSomeNumbers(int a, int b) { return a+b; }
}
mixin FancyMain!MySite;
web.d automatically generates the form you see there, parses the url into the types given, and formats the return value into either html, json, or sometimes other things (for example, objects can be made into tables).
There is also an envelopeFormat url param that can wrap it in more json, best for machine consumption:
http://arsdnet.net/cgi-bin/apidemo/add-some-numbers?a=1&b=2&format=json&envelopeFormat=json
web.d.php in my github shows one way you can consume it, and web.d itself automatically generates javascript functions to call from the client:
MySite.addSomeNumbers(10, 20).get(function(answer) { alert("Server replied: " + answer); });
answer would be of the type returned by the D function.
If you don't want/need the automatic function wrapping, cgi.d alone gives access to the basic info and writing functions:
void requestHandler(Cgi cgi) {
// there's cgi.get["name"], cgi.post["name"], or cgi.request("name"), kinda like php
cgi.write("hello ", cgi.request("name"));
}
mixin GenericMain!requestHandler;
But yeah, most the documentation that exists for my library is just me talking about it on forums... I think once you've done one function it isn't hard to figure out, but I'm biased!
edit: copy/paste from my comment below since it is pretty relevant to really getting RESTy:
I actually did play with the idea of having urls map to objects and the verbs go through: web.d also includes an ApiObject class which goes: /obj/name -> new Obj("name"); and then calls the appropriate methods on it. So GET /obj/name calls (new Obj("name")).GET();, same for POST, PUT, etc. Then /obj/name/foo calls (new Obj("name").foo(); with the same rules as I described for functions above.
But I don't use it as much as the plain functions for one because it is still somewhat buggy.... and it is still somewhat buggy because I don't use it enough to sit down and fit it all! lol
You use it by writing an ApiObject class and then aliasing it into the ApiProvider:
import arsd.web;
class MySite : ApiProvider {
export int addSomeNumbers(int a, int b) { return a+b; }
alias MyObject obj; // new, brings in MyObject as /obj/xxx/
}
And, of course, define the object:
class MyObject : ApiObject {
CoolApi parent;
string identifier;
this(CoolApi parent, string identifier) {
this.parent = parent;
this.identifier = identifier;
/* you might also want to load any existing object from a database or something here, using the identifier string, and initialize other members */
// for now to show the example, we'll just initialize data with dummy info
data.id = 8;
data.name = "MyObject/" ~ identifier;
}
/* define some members as a child struct so we can return them later */
struct Data {
int id;
string name;
Element makeHtmlElement() {
// for automatic formatting as html
auto div = Element.make("div");
import std.conv;
div.addChild("span", to!string(id)).addClass("id");
div.appendText(" ");
div.addChild("span", name).addClass("name");
return div;
}
}
Data data;
export Data GET() {
return data;
}
export Data POST(string name) {
parent.ensureGoodPost(); // CSRF token check
data.name = name;
// normally, you'd commit the changes to the database and redirect back to GET or something like that, but since we don't have a db we'll just return the modified object
return data;
}
// property accessors for the data, if you want
export int id() {
return data.id;
}
}
mixin FancyMain!MySite;
Then you can access it:
http://arsdnet.net/cgi-bin/apidemo2/obj/cool/
BTW the trailing slash is mandatory: this is one of the outstanding bugs I haven't gotten around to fixing yet. (The trailing slash code is more complicated than it should be, making this harder to fix that it might look.)
Anyway, you can see the object rendered itself as html via makeHtmlElement. This is a good time to showcase other formats:
http://arsdnet.net/cgi-bin/apidemo2/obj/cool/?format=table
table, also try csv, and of course, json
http://arsdnet.net/cgi-bin/apidemo2/obj/cool/?format=json
or for machine consumption:
http://arsdnet.net/cgi-bin/apidemo2/obj/cool/?format=json&envelopeFormat=json
and the property is available too:
http://arsdnet.net/cgi-bin/apidemo2/obj/cool/id
Another major outstanding bug is that the automatically generated Javascript functions can't access child objects at all. They only work on functions on the top level ApiProvider. Another bug that is harder to fix than it might seem, and I'm not particularly driven to do so because the top-level functions can do it all anyway. Of course, you could make the URLs yourself on the xmlhttprequest and access it that way.
Let's also demo POST by slapping together a quick form:
http://arsdnet.net/cgi-bin/apidemo2/poster
you can submit something and see the POST handler indeed reset the name. (BTW note the action has that trailing slash: without it, it silently redirects you! I really should fix that.)
Anyway, bugs notwithstanding, the core of it works and might be the closest thing to full blown REST D has right now.
At the moment of writing this text there is no framework for building true RESTful web services that I know of. However, you should be able to easily build one on top of vibe.d or Adam's web modules that he already mentioned above.
You can take a look at what I'm building. Still extremely alpha, but I'm attempting to build a Rails-like framework in D: http://jaredonline.github.io/action-pack/
I know this is a really late answer, but I figured someone might come by this one day, since it has been so long and a lot of changes has happened within the D community, especially towards web development.
With Diamond you can write RESTful web applications without hacking something together, since it supports it within the framework.
http://diamondmvc.org/docs/backend/#rest
You can try Hunt Framework.
routes setting
GET /user/{id} user.detail
app/UserController.d souce code:
module app.controller.UserController;
import hunt.framework;
class User
{
int id;
string name;
}
class UserController : Controller
{
mixin MakeController;
#Action
JsonResponse detail(int id)
{
auto user = new User;
user.id = id;
user.name = "test";
return new JsonResponse(user);
}
}
Request http://localhost:8080/user/123
{
"id": 123,
"name": "test"
}
I'm working on a sample app for Facebook, using Flash Builder and Flex.
Now, I've got everything up and running - but there's one problem, specifically with the work history part.
When I try to display the user's work history..here's the code for logging in:
protected function login():void
{
FacebookDesktop.login(loginHandler, ["user_birthday", "user_work_history"]);
}
Here, loginHandler's a callback function, that then goes ahead and displays data about the user:
protected function loginHandler(success:Object,fail:Object):void
{
if (success){
currentState = "LoggedIn";
fname.text = success.user.name;
userImg.source=FacebookDesktop.getImageUrl(success.uid,"small");
birthdayLbl.text=success.user.birthday;
workLbl.text=success.user.work;
}
}
Now, the problem occurs with success.user.work - it ends up printing the following:
[object,Object],[object,Object],[object,Object],[object,Object]
Obviously, I'm doing something wrong..but I can't figure out what exactly it is. Would be grateful for some pointers!
Thanks!
Rudi.
The object contained in success.user.work is most likely an array of objects, each item representing a work period, so you'll have to treat it as such. Either use a list and a custom renderer for each item, or create a string by iterating over the array, and appending the fields that you're interested in.
To see what the individual objects contain, either use a breakpoint during debug and inspect them, or check to see if they're documented in the facebook development documentation.
I'm looking specifically for a way to automatically hyphenate CamelCase actions and views. That is, I'm hoping I don't have to actually rename my views or add decorators to every ActionResult in the site.
So far, I've been using routes.MapRouteLowercase, as shown here. That works pretty well for the lowercase aspect of URL structure, but not hyphens. So I recently started playing with Canonicalize (install via NuGet), but it also doesn't have anything for hyphens yet.
I was trying...
routes.Canonicalize().NoWww().Pattern("([a-z0-9])([A-Z])", "$1-$2").Lowercase().NoTrailingSlash();
My regular expression definitely works the way I want it to as far as restructuring the URL properly, but those URLs aren't identified, of course. The file is still ChangePassword.cshtml, for example, so /account/change-password isn't going to point to that.
BTW, I'm still a bit rusty with .NET MVC. I haven't used it for a couple years and not since v2.0.
This might be a tad bit messy, but if you created a custom HttpHandler and RouteHandler then that should prevent you from having to rename all of your views and actions. Your handler could strip the hyphen from the requested action, which would change "change-password" to changepassword, rendering the ChangePassword action.
The code is shortened for brevity, but the important bits are there.
public void ProcessRequest(HttpContext context)
{
string controllerId = this.requestContext.RouteData.GetRequiredString("controller");
string view = this.requestContext.RouteData.GetRequiredString("action");
view = view.Replace("-", "");
this.requestContext.RouteData.Values["action"] = view;
IController controller = null;
IControllerFactory factory = null;
try
{
factory = ControllerBuilder.Current.GetControllerFactory();
controller = factory.CreateController(this.requestContext, controllerId);
if (controller != null)
{
controller.Execute(this.requestContext);
}
}
finally
{
factory.ReleaseController(controller);
}
}
I don't know if I implemented it the best way or not, that's just more or less taken from the first sample I came across. I tested the code myself so this does render the correct action/view and should do the trick.
I've developed an open source NuGet library for this problem which implicitly converts EveryMvc/Url to every-mvc/url.
Uppercase urls are problematic because cookie paths are case-sensitive, most of the internet is actually case-sensitive while Microsoft technologies treats urls as case-insensitive. (More on my blog post)
NuGet Package: https://www.nuget.org/packages/LowercaseDashedRoute/
To install it, simply open the NuGet window in the Visual Studio by right clicking the Project and selecting NuGet Package Manager, and on the "Online" tab type "Lowercase Dashed Route", and it should pop up.
Alternatively, you can run this code in the Package Manager Console:
Install-Package LowercaseDashedRoute
After that you should open App_Start/RouteConfig.cs and comment out existing route.MapRoute(...) call and add this instead:
routes.Add(new LowercaseDashedRoute("{controller}/{action}/{id}",
new RouteValueDictionary(
new { controller = "Home", action = "Index", id = UrlParameter.Optional }),
new DashedRouteHandler()
)
);
That's it. All the urls are lowercase, dashed, and converted implicitly without you doing anything more.
Open Source Project Url: https://github.com/AtaS/lowercase-dashed-route
Have you tried working with the URL Rewrite package? I think it pretty much what you are looking for.
http://www.iis.net/download/urlrewrite
Hanselman has a great example herE:
http://www.hanselman.com/blog/ASPNETMVCAndTheNewIIS7RewriteModule.aspx
Also, why don't you download something like ReSharper or CodeRush, and use it to refactor the Action and Route names? It's REALLY easy, and very safe.
It would time well spent, and much less time overall to fix your routing/action naming conventions with an hour of refactoring than all the hours you've already spent trying to alter the routing conventions to your needs.
Just a thought.
I tried the solution in the accepted answer above: Using the Canonicalize Pattern url strategy, and then also adding a custom IRouteHandler which then returns a custom IHttpHandler. It mostly worked. Here's one caveat I found:
With the typical {controller}/{action}/{id} default route, a controller named CatalogController, and an action method inside it as follows:
ActionResult QuickSelect(string id){ /*do some things, access the 'id' parameter*/ }
I noticed that requests to "/catalog/quick-select/1234" worked perfectly, but requests to /catalog/quick-select?id=1234 were 500'ing because once the action method was called as a result of controller.Execute(), the id parameter was null inside of the action method.
I do not know exactly why this is, but the behavior was as if MVC was not looking at the query string for values during model binding. So something about the ProcessRequest implementation in the accepted answer was screwing up the normal model binding process, or at least the query string value provider.
This is a deal breaker, so I took a look at default MVC IHttpHandler (yay open source!): http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/MvcHandler.cs
I will not pretend that I grok'ed it in its entirety, but clearly, it's doing ALOT more in its implementation of ProcessRequest than what is going on in the accepted answer.
So, if all we really need to do is strip dashes from our incoming route data so that MVC can find our controllers/actions, why do we need to implement a whole stinking IHttpHandler? We don't! Simply rip out the dashes in the GetHttpHandler method of DashedRouteHandler and pass the requestContext along to the out of the box MvcHandler so it can do its 252 lines of magic, and your route handler doesn't have to return a second rate IHttpHandler.
tl:dr; - Here's what I did:
public class DashedRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
requestContext.RouteData.Values["action"] = requestContext.RouteData.GetRequiredString("action").Replace("-", "");
requestContext.RouteData.Values["controller"] = requestContext.RouteData.GetRequiredString("controller").Replace("-", "");
return new MvcHandler(requestContext);
}
}