Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions OneTimeKit/Models/OTPBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ typedef NS_ENUM(NSInteger, OTPropertiesVersion) {
// subclasses must provide a default `factor` implementation
- (uint64_t)factor;
- (NSString *)password;
- (NSString *)secret;
- (NSString *)qrString:(NSArray *)input;

- (NSArray<NSURLQueryItem *> *)queryItems;

Expand Down
9 changes: 9 additions & 0 deletions OneTimeKit/Models/OTPBase.m
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ - (NSString *)passwordForFactor:(uint64_t)factor {
for (char *valuePtr = value + digits; value < valuePtr; head /= base) {
*(--valuePtr) = (head % base) + '0';
}
//NSString* newStr = [[NSString alloc] initWithData:self.algorithm encoding:NSUTF8StringEncoding];
return [[NSString alloc] initWithBytesNoCopy:value length:digits encoding:NSASCIIStringEncoding freeWhenDone:YES];
}

Expand All @@ -186,6 +187,14 @@ - (NSString *)password {
return [self passwordForFactor:[self factor]];
}

- (NSString *)secret {
return [self.key base32EncodedStringWithOptions:NSDataBase32EncodingOptionsNoPad];
}

- (NSString *)qrString:(NSArray *)input {
return [NSString stringWithFormat: @"otpauth://totp/%@:%@?secret=%@&issuer=%@", input[0],input[1],self.secret,input[0]];
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is currently implemented in

return [self _urlForScheme:@"otpauth"];

}

- (NSDictionary *)properties {
return @{
OTPDigitPropertyKey : @(self.digits),
Expand Down
23 changes: 23 additions & 0 deletions OneTimeKit/Services/OTQRCreatorService.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// OTQRCreatorService.h
// onetime
//
// Created by owl on 14.09.24.
// Copyright © 2024 Leptos. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreImage/CoreImage.h>

@interface OTQRCreatorService : NSObject


+ (instancetype)shared;
// Declaration of a class method `generateQRCodeFromString:` which generates a QR code from a given string.
// Parameters:
// - string: The string to be encoded into a QR code.
// Returns: An UIImage object representing the generated QR code.
+ (UIImage *)generateQRCodeFromString:(NSString *)string;
+ (NSURL *)generateQRCodeFileFromString:(NSString *)string;


@end
63 changes: 63 additions & 0 deletions OneTimeKit/Services/OTQRCreatorService.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#import <Foundation/Foundation.h>
#import <CoreImage/CoreImage.h>
#import <UIKit/UIKit.h>

@interface OTQRCreatorService : NSObject

+ (UIImage *)generateQRCodeFromString:(NSString *)string;

@end

@implementation OTQRCreatorService

+ (CIImage *)generateQRCodeImageFromString:(NSString *)string {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is implemented in

- (CIImage *)codeImageForData:(NSData *)data {

// Create a CIFilter object for generating QR codes.
CIFilter *qrCodeFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"];

// Set the input data for the QR code filter from input string, converted to UTF-8
[qrCodeFilter setValue:[string dataUsingEncoding:NSUTF8StringEncoding] forKey:@"inputMessage"];

// Get the output image from the QR code filter.
CIImage *outputImage = qrCodeFilter.outputImage;

return outputImage;
}

+ (UIImage *)generateQRCodeFromString:(NSString *)string {
/*CIImage *outputImage = [self generateQRCodeImageFromString:string];
CIContext *context = [CIContext contextWithOptions:nil];
// Create a CGImageRef from the CIImage using the CIContext.
CGImageRef cgImage = [context createCGImage:outputImage fromRect:outputImage.extent];
// Create a UIImage from the CGImageRef.
UIImage *qrCodeImage = [UIImage imageWithCGImage:cgImage];
// Release the CGImageRef.
CGImageRelease(cgImage);*/

return [[UIImage alloc] initWithCIImage:[self generateQRCodeImageFromString:string]];;
}

+ (NSURL *)generateQRCodeFileFromString: (NSString *)string {

UIImage *uiImage = [[UIImage alloc] initWithCIImage:[self generateQRCodeImageFromString:string]];

NSData *NSuiImage = UIImagePNGRepresentation(uiImage);
//NSData *imageData = UIImagePNGRepresentation(uiImage);

// Create a temporary file path
NSString *tempDir = NSTemporaryDirectory();
NSString *tempFile = [tempDir stringByAppendingPathComponent:@"OTP.png"];

// Write the PNG data to the temporary file
[NSuiImage writeToFile:tempFile atomically:YES];

// Create a file URL for the temporary file
NSURL *fileURL = [NSURL fileURLWithPath:tempFile];

return fileURL;
}

@end
39 changes: 37 additions & 2 deletions onetime/Views/OTPassTableViewCell.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#import "../../OneTimeKit/Models/OTPTime.h"
#import "../../OneTimeKit/Models/OTPHash.h"
#import "../../OneTimeKit/Services/OTBagCenter.h"
#import "../../OneTimeKit/Services/OTQRCreatorService.h"

@implementation OTPassTableViewCell {
uint64_t _lastFactor;
Expand Down Expand Up @@ -236,6 +237,25 @@ - (void)delete:(id)sender {
[self.actionDelegate promptDeleteBag:self.bag];
}

- (void)extract:(id)sender {
UIPasteboard.generalPasteboard.string = self.bag.generator.secret;
}

- (void)createQR:(id)sender {
NSArray *inputParameter = @[self.bag.issuer,self.bag.account]; // The parameter you want to pass
NSString *inputString = [self.bag.generator qrString:inputParameter];
NSURL *qrCodeImage_URL = [OTQRCreatorService generateQRCodeFileFromString:inputString];
// Copy the file URL to the pasteboard
[UIPasteboard generalPasteboard].items = @[@{(NSString *)kUTTypeFileURL : qrCodeImage_URL}];
}

- (void)copyQR:(id)sender {
NSArray *inputParameter = @[self.bag.issuer,self.bag.account]; // The parameter you want to pass
NSString *inputString = [self.bag.generator qrString:inputParameter];
UIImage *qrCodeImage = [OTQRCreatorService generateQRCodeFromString:inputString];
// Copy the image data to the pasteboard
UIPasteboard.generalPasteboard.image = qrCodeImage;
}
// MARK: - UIContextMenuInteractionDelegate

- (UIContextMenuConfiguration *)contextMenuInteraction:(UIContextMenuInteraction *)interaction configurationForMenuAtLocation:(CGPoint)location API_AVAILABLE(ios(13.0)) {
Expand All @@ -256,6 +276,21 @@ - (UIContextMenuConfiguration *)contextMenuInteraction:(UIContextMenuInteraction
input:@"\b" modifierFlags:0
propertyList:nil];
deleteCommand.attributes = UIMenuElementAttributesDestructive;
UIKeyCommand *extractCommand = [UIKeyCommand commandWithTitle:@"Extract Token to Clipboard"
image:[UIImage systemImageNamed:@"doc.on.clipboard"]
action:@selector(extract:)
input:@"x" modifierFlags:0
propertyList:nil];
UIKeyCommand *createQRCommand = [UIKeyCommand commandWithTitle:@"Copy Token QR Code File"
image:[UIImage systemImageNamed:@"doc.on.clipboard"]
action:@selector(createQR:)
input:@"x" modifierFlags:0
propertyList:nil];
UIKeyCommand *copyQRCommand = [UIKeyCommand commandWithTitle:@"Copy Token QR Code"
image:[UIImage systemImageNamed:@"doc.on.clipboard"]
action:@selector(copyQR:)
input:@"x" modifierFlags:0
propertyList:nil];

NSMutableArray *additionalActions = [NSMutableArray array];

Expand All @@ -272,15 +307,15 @@ - (UIContextMenuConfiguration *)contextMenuInteraction:(UIContextMenuInteraction
NSLog(@"openURLCompletedSuccessfully: %@", success ? @"YES" : @"NO");
}];
}];
[additionalActions addObject:exportAction];
[additionalActions addObjectsFromArray:@[exportAction,extractCommand,copyQRCommand,createQRCommand]];
}

return [UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:nil
actionProvider:^UIMenu *(NSArray<UIMenuElement *> *suggestedActions) {
return [UIMenu menuWithTitle:@"" children:@[
[UIMenu menuWithTitle:@"" image:nil identifier:nil options:UIMenuOptionsDisplayInline children:@[
copyCommand,
deleteCommand
deleteCommand,
]],
[UIMenu menuWithTitle:@"" image:nil identifier:nil options:UIMenuOptionsDisplayInline children:additionalActions]
]];
Expand Down