Skip to content

Instantly share code, notes, and snippets.

@0xilis
Last active November 16, 2023 18:37
Show Gist options
  • Save 0xilis/4fdf458b917327e6eab9382247c3771b to your computer and use it in GitHub Desktop.
Save 0xilis/4fdf458b917327e6eab9382247c3771b to your computer and use it in GitHub Desktop.
Import Unsigned Shortcuts on iOS 15
/*
* Snoolie K
* 16 November 2023 (EST)
* Import Unsigned Shortcuts Example
*/
#import <UIKit/UIKit.h>
@interface WFFileRepresentation : NSObject
@property (readonly, nonatomic) NSData *data; // ivar: _data
@end
@interface WFWorkflowFileDescriptor : NSObject
@property (readonly, nonatomic) WFFileRepresentation *file;
-(id)initWithFile:(id)file name:(id)name;
@end
@interface WFWorkflowFile : NSObject
-(id)recordRepresentationWithError:(NSError*)err;
-(id)initWithDescriptor:(id)fileDesc error:(NSError*)err;
-(id)initWithFileData:(id)fileData name:(id)name error:(NSError*)err;
@end
@interface WFDatabase : NSObject
+(id)defaultDatabase;
@end
@interface WFDatabaseProxy : NSObject
-(void)createWorkflowWithWorkflowRecord:(id)workflowRecord nameCollisionBehavior:(int)nameCollisionBehavior error:(NSError*)err;
-(id)initWithDatabase:(id)database;
@end
@interface WFShortcutExtractor : NSObject
@property (readonly, nonatomic) WFFileRepresentation *extractingFile;
-(void)extractShortcutWithCompletion:(id)completion;
-(id)initWithURL:(NSURL *)url allowsOldFormatFile:(BOOL)allowOldFileFormat suggestedName:(NSString *)suggestName sourceApplication:(NSString *)app;
@end
#define UNSIGNED_SHORTCUT_PATH "/Users/0xilis/Downloads/0/GitGub/WorkflowKit-Ent-Testing/unsignedShortcut.shortcut"
/* Notice: recordRepresentationWithError: method requires com.apple.developer.icloud-services entitlement to list CloudKit. WFDatabase/WFDatabaseProxy may also require entitlements, I'm not sure :P */
int main(void) {
/* load WorkflowKit framework */
NSBundle *container = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/WorkflowKit.framework"];
if ([container load]) {
/* get classes */
Class WFWorkflowFileDescriptorClass = objc_getClass("WFWorkflowFileDescriptor");
Class WFWorkflowFileClass = objc_getClass("WFWorkflowFile");
Class WFDatabaseClass = objc_getClass("WFDatabase");
Class WFDatabaseProxyClass = objc_getClass("WFDatabaseProxy");
Class WFShortcutExtractorClass = objc_getClass("WFShortcutExtractor");
/* get WFWorkflowRecord from file */
WFShortcutExtractor* shortcutExtractor = [[WFShortcutExtractorClass alloc]initWithURL:[NSURL fileURLWithPath:@UNSIGNED_SHORTCUT_PATH] allowsOldFormatFile:YES suggestedName:@"suggestedName" sourceApplication:nil];
/* this doesn't actually call the completion method like it should for some reason but its fine since afterward we should have extractingFile */
[shortcutExtractor extractShortcutWithCompletion:^(id arg0, id arg1){
NSLog(@"we here");
NSLog(@"arg0: %@",arg0);
NSLog(@"arg1: %@",arg1);
}];
WFFileRepresentation *fileRep = [shortcutExtractor extractingFile];
WFWorkflowFileDescriptor *fileDesc = [[WFWorkflowFileDescriptorClass alloc] initWithFile:fileRep name:@"SnoolieShortcut"];
WFWorkflowFile *wFile = [[WFWorkflowFileClass alloc] initWithDescriptor:fileDesc error:nil];
WFWorkflowRecord *workflowRecord = [wFile recordRepresentationWithError:nil]; /* requires cloudkit entitlement */
/* now actually add shortcut to database */
WFDatabaseProxy *databaseProxy = [[WFDatabaseProxyClass alloc]initWithDatabase:[WFDatabaseClass defaultDatabase]];
[databaseProxy createWorkflowWithWorkflowRecord:workflowRecord nameCollisionBehavior:0x0 error:nil];
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment