Set files/folders read/write attributes in user Pythonista main folder
Hi, in Pythonista do you know a way to set a folder with read/write protection/attributes?
I mean, I’d like to set a folder “test_folder” (for example) in Pythonista main folder so that every python script inside “test_folder” and executed by interpreter can’t read or write (delete) folders and files in parent folders (top folders).
This feature should be activate or deactivate only by hand in Pythonista settings, because if a script could modify programmatically the read/write attributes of folder “test_folder” it would be a security issue.
For example, let’s suppose I create a folder named “test” in a folder named “parent_1” in Pythonista folder, see tree below:
- Pythonista main folder (Documents)
and I create inside “test” a python script named “run.py” (for example) that tries to read content of files or other folders in folder “parent_1”. Well, I’d like to set in Pythonista settings (manually and only manually) that “run.py” can’t read or modify nothing is out from “test”, in order to be sure that script “run.py” can’t create problems to other files or folders that I have in my Pythonista app. In the same way I'd like to be able to re-set (manually and only manually) folder "test" so that script "run.py" can read or modify anything inside "parent_1" or top folders.
Thank you for any answer,
- Pythonista main folder (Documents)
@JonB Hi, yes you are right, my intent is to have a secure environment in Pythonista app where I can be sure about any script that I download from web and run, without to see inside each single script if there is something strange.
I found pysandbox library on GitHub and it seems powerful, I have not tried it, but I've read also that the project is abandoned by author due to some security issues related to the limit to have a 100% secure environment using only Python language (the author says: "WARNING: pysandbox is BROKEN BY DESIGN, please move to a new sandboxing solution (run python in a sandbox, not the opposite!)"). Link of an interesting article about it here.
So my definitive solution is for now to have both Pythonista2 and Pythonista3, with one I want to test anything, with the other one I want to have tested and secure scripts.
About my solution, I noticed that if I run the library PhoneManager (link at my previous post) with Pythonista2 I can see Pythonista3 files and folders because I can surf on directories, but if I run PhoneManager with Pythonista3 I can't surf to Pythonista2 main folder (that is: I can't see that folder).
It is ok for you or not? In my opinion for sandboxing ios feature, Pythonista2 should not see the content of Pythonista3 with any pure or not pure python script or library (they are two different external ios apps) and viceversa. Why by using Pythonista2 I could delete files in Pythonista3?
Pysandbox is "broken by design" because there are ways to break out of the sandbox. Think of web based python REPL environments, you don't want someone to be able to break out and start deleting files.
But for casual use, it would be fine -- i.e if you are downloading any sort of reputable repos, or even do some even cursory look over the code, it will be ok. Again pysandbox only would work in py2.7 on pythonista, since the py3 version requires some c code.
pythonista 2 and 3 share the same publisher and we're published as a common app group. This allows two apps to share a common app group folder.
Each app also does have another app-only folder. So, it might be possible to remap the pythonista2 userpath to point to a py2 writeable only folder. That would make it harder for a script to "find" the shared folder. Since a script wouldn't know how to find the shared path, and you cannot get there by just doing listdir or os.walk, etc, that would be fairly secure too.
I forget how to find that folder... I think there is an objc method to find it, or maybe by finding the executable, and navigating up from there...
@Matteo just as some more info:
~ maps to appgroup/ (where appgroup is some long uuid based folder name)
On Pythonista3, ~ maps to appgroup/Pythonista3
thus you can get to pythonista 2 from 3 via
Or 3 from 2 via
phonemanager starts in ~, and never tried to go up from there, which is why you can see 3 from 2, but not 2 from 3. But from python, you could access either from either, if you know where to look.
Ok, one other option... If you create a folder with no read access, and monkey patching userpath to point to a subfolder, it would be hard for a script to break out.
~/Documents/sandbox (no read access)
~/Documents/sandbox/script1/ (normal access)
When a script starts in script1, if it tries to os.chdir(..), it will get an access error. And if you replace userpath, it won't know how to get to any other folders. This would also probably hide sandbox from pythonista, so use with care...
@JonB, Hello, thank you so much for your info.
So I learned something new, but why I can't set in Pythonista3 an option (manually and only manually) in order to hide main folder of Pythonista3 when I'm using Pythonista2?
I know I can see Pythonista2 files (and copy them) from Pythonista3 if I set the option "Pythonista 2 Files" in Pythonista3 settings, but I find it strange that I can't hide Pythonista3 from Pythonista2 if I want it.
If I have both Pythonista2 and Pythonista3 installed on my iPhone, I'm using Pythonista2 and I run the following script in Pythonista2 (with top = '/'),
import os top = '#!#!# warning!!!' for root, dirs, files in os.walk(top, topdown=False): for name in files: os.remove(os.path.join(root, name)) for name in dirs: os.rmdir(os.path.join(root, name))
I suppose it deletes all files also in Pythonista3, but I don't want it. If the two apps are independent from a ios point of view, it would better in my opinion to allow user to set or unset the possibility to see Pythonista3 content and modify it from Pythonista2 (only for security reasons).
I can understand it is useful to have a shared folder for both apps, but at least user should decide, with a manual option in Pythonista3 (only manual), if Pythonista3 can share the same user folder with other apps, first of all Pythonista2; this in order to have a full sandbox environment in the same idevice for those who are lucky enough to have both Pythonista2 and Pythonista3 installed.
Hi @cvp, thank you for info about filenav, it is also a powerful tool like PhoneManager, but I'm really not interested in choose a file manager for Pythonista, the built-in one is enough for me. I referred to PhoneManager program only to prove that when user run PhoneManager (and maybe filenav) in Pythonista2, the program can see content of Pythonista3, because (@JonB said) the two apps share the same user writable folder. But I don't like this choice at all, at least I'd like to be able to choose to have a shared folder between the two apps or to hide all content of Pythonista3 from full Pythonista2 app, with an option that can only be set manually.
Have you some other hints or it is impossible to hide Pythonista3 content from Pythonista2 or other apps?
As I alluded to before, there are two writable folders: the appgroup, which is shared, and the app specific folder, which is not.
@omz decided to have the file manager see the appgroup, which for most people was the right choice, since it allowed you to easily copy files over before the share menu or iCloud worked. You can't change that decision, so you have to work around it. If an app has access to a file, you could chmod it so it no longer has access, but then that works affect both apps, since both are run as the same posix user.
You could dig up the app specific folder, and put files to protect there. You won't be able to navigate there using the built in file menu, although MAYBE you could create a symbolic link in the appgroup to the app specific folder, but I'm not sure whether the pythonista file menu will honor those, or crash, etc .
You would use, I think,
If you go to that folder in stash, you should be able to get there only in the current app, not the other one.
I think you are sort of making this more complicated than it needs to be -- you are not leaving your device unattended with free access exposed to the internet... Backup your device periodically. Don't run scripts that are called delete_all_files.py. maybe skim the code before running it.
If you want to get fancy, use run_py with a globals set to use fake versions of dangerous modules, ala pysandbox. have your tried pysandbox yet? If it works, then anything you download is likely not going to be breaking out.
yup, this works:
from objc_util import * import os d=str(ObjCClass('NSFileManager').defaultManager().URLsForDirectory_inDomains_(9, 1).path()) #create symlink, lets you chdir in stash os.symlink(d,os.path.expanduser('~/Documents/private'))
but really only within stash, since the script browser doesnt honor symlinks.
@JonB Hi, first of all thank you for your continuous suggestions, much appreciated.
Unfortunately I'm so ignorant that the code you wrote for me is like a mixture of Burmese, Cyrillic and Chinese. Sorry for this
I can't understand what works about the code you wrote, that is: if I run that script in Pythonista code editor it does not work while if I run it in StaSh it works?
And what should I see? That Pythonista3 becomes invisible with respect to Pythonista2 after the execution? So, if I'm right, by executing that strange objc code in StaSh I can hide Pythonista3 from Pythonista2 and the code you wrote can be executed only in StaSh (and this prevents any other script executed in Pythonista from bypassing the changes made by running your script)?
Thank you JonB for you patience, and sorry if I have some requests that can't be converted in a simple code or setting.
PS: I will try surely pysandbox but not with Pythonista2 or 3 because I know that if I do some experiments with it (for example: file deletion test in a sandboxed folder created with pysandbox), I could delete all my Pythonista3 content also if I use Pythonista2. I will try pysandbox in a virtual machine with a standard python distribution by using my PC.
Pysandbox won't delete anything. It's a reputable open source project that you can skim through...
For my code, you would have to give up on the pythonista file menu, and move all of your files to the private folder. Then, it is protected from the other pythonista. You would need to use stash to open files, or maybe PhoneManager. Not worth it, in my opinion!
A last option is to move all of your files to a subfolder of the iCloud folder, which does not exist in pythonista2. The drawback is that you need enough iCloud storage room.
using stash, in py2.7 mode:
pip install pysandbox
then, copy execfile.py from pysandbox github repo to your library.
to run, you would then longpress execfile, type the full path of the file you want to run safely, and press run in py2.7. by default, the locks you down tighter than you will need -- for instance, you cannot even import modules. you will need to figure out the appropriate options for your level of paranoia.
@JonB Ok understood!
About pysandbox, yes I'm agree with you that pysandbox doesn't delete anything, the problem is that if I want to test pysandbox on Pythonista2 by activate some sandbox features in order to try to create a sandbox environment in Pythonista2, I definitely would try the effectiveness of the system by running the script I wrote in post #12 and if I did something wrong with pysandbox setting I would delete everything in both Pythonista2 and Pythonista3 (yes I could perform a backup of all and move it somewhere...). So no problem with pysandbox, the problem exists if I test, by trying to delete something, pysandbox effectiveness.
About your code, to know that you knows these things surprises me every time. I will try the code in both Pythonista2 and 3 by moving some files of a test folder in private folder (following your instructions), in order to see if I can work easly with these files also using StaSh (and giving up the convenient file browser of Pythonista). If I will find it hard, I will not worry anymore and I will try some suspicious scripts with some other different python app (in app store there are some of them but you can not compare them with Pythonista) or with sagecell.
Last thing: I was interested in the question mainly from a practical point of view (I wanted to have a solution that made Pythonista3 invisible from Pythonista2); then the interest became more theoretical and I asked myself if at the programming level of the Pythonista3 application it is possible for @omz to add an option that allows the user to choose whether to have a shared folder between Pythonista2 and 3 or not, so, if not, the Pythonista3 content can not be seen in any way by Pythonista2 (even by using strange objc codes executed on Pythonista2).
Thank you again
To test pysandbox, simply create a test file, then try to delete it, or overwrite it.
@omz is no longer supporting pythonista2, I doubt you will get a new option. (And since no one uses pythonista2 anymore, it wouldn't make much sense to to add those features to pythonista3). Plus, your whole premise is flawed to begin with ... If you have anything worth saving, you should be backing up.
I will point out a middle ground which is this:. If you place unsafe files in the private folder, and del os.path.expanduser, and pathlib.Path.home, and sanitize sys.path, then you should be able to run untrusted code, since those files have no way of knowing how to find the shared folder. iOS prevents them from doing listdir in the parent of the app folder or group folder, so it is impossible for another app to find the files to delete (unless it is a script specifically targeting YOU. But if you are worried about that, you shouldn't ever take your iPad out of it's tin foil package to begin with)
@JonB Hi, ok thank you for useful info, I’m testing pysandbox in a virtual machine on my pc.
If I will be satisfied with some tests I want to perform (for example the execution of a script that tries to read something out the folder in which it is saved but that can import any modules from external standard ‘site-packages’ folder), then I will install pysandbox also in Pythonista.
Obviously if the script I try to run can’t import external modules, it is not so easy/useful to use (in my opinion).
A solution could be to copy manually inside the folder (where there is the potentially dangerous script to be executed) all the required modules by copying them from folder site-packages: in this way, if there are all the required modules in the same folder, maybe the script can be run.
In other words, a potentially dangerous script should always, in my opinion, be able to read modules in site-packages (but not be able to modify or delete them if user wants it), but should not read or modify or delete files or modules in other folders that are set "private" by the user (I will try to understand if it is possibile with pysandbox, and I wanted also that it could be done manually in Pythonista settings, and it is the reason I started all the discussion).
I still have to understand also if pysandbox creates a sandbox environment only for the potentially dangerous scripts or for the scripts (or files or folders) that I want to protect by the potentially dangerous scripts.
These are the arguments I'm studying in these period (in my spare time) to understand how the iOS sandbox feature works (as a personal curiosity).
For now I’d like to ask you other things I’m interested about:
Do you know if it is possible for any app (installed from Apple Store) to read or delete files and folders in Pythonista main folder if that app knows the full and absolute path of my Pythonista ‘Documents’ folder that is something like
/private/var/......../Documents/...? If yes, why it would be possible? Where is the iOS sandbox feature in this situation? I mean, if I know where to search, the sandbox feature should in my opinion give me no chance to access to sandboxed folders and files even if I know where to search, as for a thief who knows where is my house (the full absolute path) and tries to opens the door that is closed with a very strong lock (the read-write protection by sandboxing, with password request for read-write access, for example).
Do you know if a python script (and if yes how could this script be written) can read or delete files and folders in Pythonista ‘Documents’ main folder if that script knows its full and absolute path, like for the app of point 1? Also in this situation, how can user defend own files? Only with backup? But if the user is only afraid that the files will be read without his/her knowledge by that script? In other words, can a python script search not in subfolders, starting from a folder, but in upper/parent folders in a recursive way in order to try to read confidential files saved in folders outside the one in which this script is executed?
Sorry for these questions, but I'm mainly interested about these arguments in this period and I find very nice to discuss these things with the people of this forum, that are very skilled but also very humble in giving information.
An app cannot write to the APP folder of another app. That is enforced by kernel restrictions. I described above how to find the app folder -- you can try it (see if you can get to the pythonista2 APP folder from pythonista 3)
Apps signed by the same developer can share files in the APPGOUP folder. By default, pythonista has all of it's user files in the app group folder.
If you want to get pysandbox working in pythonista, you should be using it in pythonista, because it will work differently on your desktop, since there is can use c extensions, etc. Obviously, you will write your own test cases, so there is no danger (you can create dummy files in site packages that you try to delete)
You will need to create a wrench item that runs a script using pysandbox, or else run via stash -- it won't somehow modify your environment permanently (how could it!).
You will need to define a whitelist for the path for files you want to allow reading (see safe_open.py -- this replaces python open in sandboxed scripts, and allows only read access, and only to folders you specify). You could modify safe_open to allow write access to specific folders, but as written it will only permit reading, and only from folders you tell it.
See safe_import for how imports happen.
Again, you specify a whitelist.
In my opinion, you are wasting your time. If you skim a script before you run it, you will get an idea about whether it is going to be totally malicious. And periodic backups protect you from whatever slips through. Maybe a wrench script that lists all imports, and lists all open, shutil, os, ctypes, objc_util, etc usage in a folder would go a long way to easing your mind?
If your concern is about reading confidential files (versus writing files, etc) then one option is to keep sensitive files encrypted in the app (not appgroup) folder, and have wrench items that move files in/out of that "vault". Basically you have a "lockdown" wrench item, and an "unlock" wrench item. This would be slow but probably you would only lockdown critical files.
You would likely chmod that folder to remove execute access, preventing anyone from reading the directory.