Applet Permissions

Hi folks,

Me again, trying to figure out this head scratcher and hoping someone here has an idea on what to do here, I have an applet I’ve been trying to build, I have a functioning app on some systems but I am unable to transfer this between devices, I can transfer the code and re-compile it on each device that I use this on but that’s an extra step I’m trying not to have.

I would ideally love to have where I essentially have an applet that I can transfer between systems or send to another person if they need it to help, when I do that I get and error that the system doesn’t have permission to open the file, I have changed the permissions on all the files to allow everybody read and write permissions, I’m wondering if there is something I need to add to the app itself to get this to allow access, currently all the workbooks are stored in the app itself under Contents:Resources folder within the app itself.

This is one of the errors I’ve been seeing:

Here is the code as it stands:


use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use framework "Foundation"

set appFile to (path to me as string) & "Contents:Resources:filecheck.txt" -- Path to Version check resources
set rosterPath to (path to me as string) & "Contents:Resources:Rosters:" -- Path to Roster folder
set activeSheet to (path to me as string) & "Contents:Resources:Active Sheet:" -- Path to Active Sheet Files folder
set desktopFolder to (path to desktop folder as string) -- Path to Desktop Folder
set rosterFiles to {"Roster1.numbers", "Roster 2.numbers", "Roster 3.numbers", "Roster 4.numbers"}
set docName to {} -- Placeholder for Roster files
set formSheet to "Roster" -- Roster Sheet
set peopleTable to "People Input" -- People Table
set formMonth to "Monthly Sheet" -- Monthly Sheet
set sheetLog to "Time Log" -- Time Log
set linesBusiness to {"Option 1", "Option 2", "Option 3", "Option 4"} -- LOB List
set theDate to short date string of (current date) -- Read current date (Condensed)
set shortDate to date string of (current date) -- Short date (Just Date)
set currentDate to current date -- Complete date and time
set listLOB to {}

tell application "Finder"
	
	set fileCreationDate to modification date of file appFile
	set daysDifference to {currentDate - fileCreationDate} / days
	
	if daysDifference < 180 then
		
		tell application "System Events"
			set folderContents to name of every file in folder activeSheet
		end tell
		
		repeat with fileName in rosterFiles
			if fileName is in folderContents then
				set docName to activeSheet & fileName
				set listLOB to fileName
				exit repeat
			end if
		end repeat
		
		if listLOB is {} then
			
			set listResult to item 1 of (choose from list linesBusiness with prompt "Choose a Line of Busines:" default items {item 1 of linesBusiness}) -- LOB Selection
			set listLOB to item 1 of listResult -- Get the selected file from the list
			
			if listResult = "Option 1" then
				
				set fileToCopy to rosterPath & "Roster 1.numbers" as text
				duplicate file fileToCopy to folder activeSheet
				delay 7
				set fileToOpen to activeSheet & "Roster 1.numbers" as text
				set docName to fileToOpen
				
			else
				if listResult = "Option 2" then
					
					set fileToCopy to rosterPath & "Roster 2.numbers" as text
					duplicate file fileToCopy to folder activeSheet
					delay 7
					set fileToOpen to activeSheet & "Roster 2.numbers" as text
					set docName to fileToOpen
					
				else if listResult = "Option 3" then
					
					set fileToCopy to rosterPath & "Roster 3.numbers" as text
					duplicate file fileToCopy to folder activeSheet
					delay 7
					set fileToOpen to activeSheet & "Roster 3.numbers" as text
					set docName to fileToOpen
					
				else if listResult = "Option 4" then
					
					set fileToCopy to rosterPath & "Roster 4.numbers" as text
					duplicate file fileToCopy to folder activeSheet
					delay 7
					set fileToOpen to activeSheet & "Roster 4.numbers" as text
					set docName to fileToOpen
					
				end if
				
			end if
		end if
		
		
		display dialog "What Role are you filling today?" buttons {"Roster", "Time Log", "Cancel"} default button "Roster" giving up after 45 -- Initial Input to either open roster or time log
		
		if button returned of result = "Roster" then
			
			tell application "Numbers"
				launch
				activate
				set myDoc to open (docName) as alias
				tell document 1
					set active sheet to sheet formSheet
					tell table peopleTable of sheet formSheet
						set endDate to value of cell "A10"
					end tell
					if currentDate ≥ endDate then
						display dialog "Did your assignment end on " & endDate & "?:" buttons {"Yes", "No"} default button "Yes"
						if button returned of result = "Yes" then
							tell application "Finder"
								duplicate file docName to desktopFolder with replacing
								quit
								delay 3
								delete file docName
							end tell
						else if button returned of result = "No" then
							set loanEnd to text returned of (display dialog "When does your assignment end? (MM/DD/YYYY)" default answer "")
							tell table peopleTable of sheet formSheet
								set value of cell "A10" to loanEnd
							end tell
						end if
					end if
				end tell
			end tell
			
		else if button returned of result = "Cancel" then
			
			quit
			
		else if button returned of result = "Time Log" then
			
			set columnCount to 5
			set rowCount to 5
			set headerRow to 1
			set headerColumn to 0
			set timeStarted to text returned of (display dialog "Enter the time started: (24hr)" default answer "") -- Start Time
			set timeFinished to text returned of (display dialog "Enter the time finished: (24hr)" default answer "") -- Finish Time
			set taskList to {"Option 1", "Option 2", "Option 3", "Option 4", "Option 5", "Option 6", "Option 7", "Option 8", "Option 9", " "} -- Task list
			set theTask to item 1 of (choose from list taskList with prompt "Choose a task:" default items {item 1 of taskList}) -- Task selection
			set columnList to {"A", "B", "C", "D", "E"} -- Column Header values
			set headerList to {"Date:", "Time Started:", "Time Finished:", "Time Taken:", "Task Completed:"} -- Table column values
			set theDuration to my getDuration(timeStarted, timeFinished) -- Calculate time take on task
			set valueList to {theDate, timeStarted, timeFinished, theDuration, theTask} -- Table variables for input
			
			tell application "Numbers"
				
				launch
				activate
				set myDoc to open (docName) as alias
				tell sheet sheetLog of document 1
					if not (exists table 1) then
						
						set theTable to make new table with properties {header row count:headerRow, column count:columnCount, row count:rowCount, header column count:headerColumn, header columns frozen:"False", name:shortDate}
						
						repeat with i from 1 to 5
							set value of cell i of row 1 of theTable to item i of headerList
							set alignment of cell i of row 1 of theTable to center
						end repeat
						
					end if
				end tell
			end tell
			
			tell application "Numbers"
				activate
				tell table 1 of sheet sheetLog of document 1
					
					repeat with rowNumber from 1 to 100
						
						try
							set cellValue to value of cell ("A" & rowNumber)
							if cellValue is (missing value) then exit repeat
						on error
							add row below last row
							exit repeat
						end try
					end repeat
					
					repeat with i from 1 to 5
						set value of cell ((item i of columnList) & rowNumber) to (item i of valueList)
					end repeat
				end tell
			end tell
		end if
		
	else
		display dialog "The file is out of Date, please download a new copy" buttons {"Cancel", "Open Link"} default button "Open Link" giving up after 45
		set the button_pressed to the button returned of the result
		if the button_pressed is "Open Link" then
			open location "www.google.com"
			quit
			return {}
		end if
	end if
end tell


on getDuration(startTime, finishTime)
	set {TID, text item delimiters} to {text item delimiters, ":"}
	set startMinutes to ((text item 1 of startTime as integer) * 60) + (text item 2 of startTime as integer)
	set finishMinutes to ((text item 1 of finishTime as integer) * 60) + (text item 2 of finishTime as integer)
	set durationHours to (finishMinutes - startMinutes) div 60
	set durationMinutes to (finishMinutes - startMinutes) mod 60
	set text item delimiters to TID
	return (durationHours as text) & " hours " & durationMinutes & " minutes"
end getDuration

You all have been an amazing assistance with the trial and error of learning this and appreciate all the help you all have provided already.

Regards,

Mark

When your application uses scripting to command another app, especially one that can access sensitive information, it requires permission from the user - this is what the system is talking about, not the regular read/write permissions. In addition, applications are normally code signed these days, but unless the certificate is from a known Certification Authority (Apple in this case), the system won’t trust it - this has been the system security model for the last several OS versions.

Administrative permission can still be granted or quarantine attributes removed in order to open these kinds of applications (with the assumption that you know where it is coming from and what it does), in which case a permissions dialog will be presented when the app is first run. Current script editors make permissions usage key/value entries in the application Info.plist file for these dialogs, but if you are using older versions you can also run into issues if the entries are not there.

Hey red_menace,

This is where the conundrum comes into play, I have a dev account, I have code signed the app when compiling it, I allow the app to have full disk access via system settings > security & privacy, I can run the app no issue and it then asks on first for permission to script the apps, it doesn’t have issues there, the issue comes when it’s trying to open or save the workbooks, that’s when it gives the permissions error.

Which is why I’ve been driving myself round the bend trying to fathom this out, I can build it and run it on a completely different user on the same system as I build it with no issues, as soon as I copy it to another device then I start getting either 61 or 45 errors which are both permission related.

Looking closer at your script, it appears that you are writing to the application bundle, which is usually a big no-no since that can break the code signing. You might take a look at copying these resources to a folder in the Application Support folder and using that. You may also need to set up a secure bookmark for access to the Desktop, since the user hasn’t navigated there to set up an intent.

Note that there are standard ways to get paths to application resources, such as path to resource, so you can avoid using System Events for that.

Hey Red,

Well that might answer the permissions issues but it doesn’t answer the ultimate question of use, because of what I am using this for, essentially to work with managing multiple teams of people at once or individually, I need to send this out to people then have them fill out the spreadsheets, save it back to the app to be transferred back, so ideally I’m looking for something that can be saved to the app and then transferred.

I don’t know if there’s somewhere else within an applet that you can use for this, just when I was looking the only option I could find was the resources folder, honestly this is still a journey for me, I’m teaching/exploring AppleScript for myself before delving into ASObjC and then looking to possibly expanding into Swift, so right now any knowledge or experience is really helpful.

The application bundle is definitely not where you should be trying to save user files - the Application Support folder is where app-created support and configuration files should be placed. I’ve used a folder within ~/Library/Application Support to save default and custom configuration property lists for various apps (note that for sandboxed apps, the system provided methods should be used to get paths within its container, as the app won’t have access to the real ones). NSUserDefaults can be used to save preferences, including the configuration file to load on startup.

If these are just regular files, perhaps you could add a menu option to zip the file or contents of the folder, possibly even automate sending it to you.

Hey Red,

Having read through your comment this is now what I am going to do, essentially going back to an earlier revision with some changes, so when I select the file for the group I’m needing it will check if a file on the desktop exists if it does not it will create it, then it will save the file to that location, then I just will run the app as more of a background task, this should then resolve some of the permission issues because otherwise all of the other features do work, this was just my niggling one, I would have liked to have had it self contained if I could but it appears that is beyond the scope of AppleScript, I’m still going to continue tinkering and building further in my own discovery, so maybe with use of ASOC with Cocoa, I might have the ability to have another folder within the app that those files can be pulled from or only saved to, otherwise possibly something I need to do with Swift as a later revision, I appreciate the info and the guidance.

Regards

It isn’t that it is beyond the scope of AppleScript, applications (especially these days) just aren’t designed to be modified or store user information - that is what things like the Application Support folder, user defaults (preferences), regular files, etc, are for. You aren’t going to have much luck trying to work around code signing and sandboxing, since Apple continually updates the system to prevent things like that.

I’m still not quite understanding the purpose for wanting to modify the application bundle. Perhaps if you expanded on the description of your workflow, such as what the “transferred back” part is for, an alternative could be worked out.

The app is mainly to perform some functions, mainly Time Log, make sure the files aren’t out of date etc, once the assignment is completed to move the file out of the directory for ease of finding etc, otherwise the real back bone of it is the Numbers spreadsheets that I have within the applet.

The "transferred back” part would be me needing to send a copy of the files to another manager for example and needing them to fill out the information in the spreadsheet for their team that I then would use whilst on that assignment, hence why a one stop shop (kind of like a variable in a sense) would be beneficial, essentially having the app move a copy of the spreadsheet that is then referenced when opened, so then it goes to the correct information or if more than one (as a future revision as it currently stands) then it would read the contents of the folder where it is stored and I can choose which spreadsheet to open and use depending on assignment, which would be why I was asking about possibly having an option inside the applet to designate a folder outside of the Resources that I could use but would still be within the applet itself.