Improve lock/unlock assurance flow.
[FIXED] Bug that caused the window to sometimes re-open when closed.
This commit is contained in:
parent
797060f609
commit
08d3d9ad30
@ -225,7 +225,7 @@
|
|||||||
<object class="NSButtonCell" key="NSCell" id="922307452">
|
<object class="NSButtonCell" key="NSCell" id="922307452">
|
||||||
<int key="NSCellFlags">67108864</int>
|
<int key="NSCellFlags">67108864</int>
|
||||||
<int key="NSCellFlags2">134217728</int>
|
<int key="NSCellFlags2">134217728</int>
|
||||||
<string key="NSContents">Enable iCloud</string>
|
<string key="NSContents">Use iCloud</string>
|
||||||
<reference key="NSSupport" ref="1068244176"/>
|
<reference key="NSSupport" ref="1068244176"/>
|
||||||
<string key="NSCellIdentifier">_NS:9</string>
|
<string key="NSCellIdentifier">_NS:9</string>
|
||||||
<reference key="NSControlView" ref="499448697"/>
|
<reference key="NSControlView" ref="499448697"/>
|
||||||
|
@ -204,7 +204,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
|
|
||||||
- (IBAction)terminate:(id)sender {
|
- (IBAction)terminate:(id)sender {
|
||||||
|
|
||||||
NSLog( @"Closing: Terminating" );
|
|
||||||
[self.passwordWindow close];
|
[self.passwordWindow close];
|
||||||
self.passwordWindow = nil;
|
self.passwordWindow = nil;
|
||||||
|
|
||||||
@ -215,7 +214,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
|
|
||||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://itunes.apple.com/app/id510296984"]];
|
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://itunes.apple.com/app/id510296984"]];
|
||||||
|
|
||||||
NSLog( @"Closing: App Store" );
|
|
||||||
[self.initialWindow close];
|
[self.initialWindow close];
|
||||||
self.initialWindow = nil;
|
self.initialWindow = nil;
|
||||||
}
|
}
|
||||||
@ -271,7 +269,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
if (![self.passwordWindow.window isVisible])
|
if (![self.passwordWindow.window isVisible])
|
||||||
self.passwordWindow = nil;
|
self.passwordWindow = nil;
|
||||||
else {
|
else {
|
||||||
NSLog( @"Closing: dialogStyleHUD && passwordWindow.isVisible" );
|
|
||||||
[self.passwordWindow close];
|
[self.passwordWindow close];
|
||||||
self.passwordWindow = nil;
|
self.passwordWindow = nil;
|
||||||
[self showPasswordWindow:nil];
|
[self showPasswordWindow:nil];
|
||||||
@ -305,8 +302,6 @@ static OSStatus MPHotKeyHander(EventHandlerCallRef nextHandler, EventRef theEven
|
|||||||
BOOL reopenPasswordWindow = [self.passwordWindow.window isVisible];
|
BOOL reopenPasswordWindow = [self.passwordWindow.window isVisible];
|
||||||
|
|
||||||
if (![[self activeUserForThread].objectID isEqual:activeUser.objectID]) {
|
if (![[self activeUserForThread].objectID isEqual:activeUser.objectID]) {
|
||||||
NSLog( @"Closing: activeUser changed: %@ -> %@, reopening: %d", [self activeUserForThread].objectID, activeUser.objectID,
|
|
||||||
reopenPasswordWindow );
|
|
||||||
[self.passwordWindow close];
|
[self.passwordWindow close];
|
||||||
self.passwordWindow = nil;
|
self.passwordWindow = nil;
|
||||||
[super setActiveUser:activeUser];
|
[super setActiveUser:activeUser];
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
@property(nonatomic, weak) IBOutlet NSProgressIndicator *progressView;
|
@property(nonatomic, weak) IBOutlet NSProgressIndicator *progressView;
|
||||||
@property(nonatomic, weak) IBOutlet NSTextField *userLabel;
|
@property(nonatomic, weak) IBOutlet NSTextField *userLabel;
|
||||||
|
|
||||||
- (void)unlock;
|
|
||||||
- (IBAction)reload:(id)sender;
|
- (IBAction)reload:(id)sender;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
@property(nonatomic, strong) NSOperationQueue *backgroundQueue;
|
@property(nonatomic, strong) NSOperationQueue *backgroundQueue;
|
||||||
@property(nonatomic, strong) NSAlert *loadingDataAlert;
|
@property(nonatomic, strong) NSAlert *loadingDataAlert;
|
||||||
|
@property(nonatomic) BOOL closing;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation MPPasswordWindowController {
|
@implementation MPPasswordWindowController {
|
||||||
@ -30,7 +31,6 @@
|
|||||||
|
|
||||||
- (void)windowDidLoad {
|
- (void)windowDidLoad {
|
||||||
|
|
||||||
NSLog(@"DidLoad:\n%@", [NSThread callStackSymbols]);
|
|
||||||
if ([[MPMacConfig get].dialogStyleHUD boolValue])
|
if ([[MPMacConfig get].dialogStyleHUD boolValue])
|
||||||
self.window.styleMask = NSHUDWindowMask | NSTitledWindowMask | NSUtilityWindowMask | NSClosableWindowMask;
|
self.window.styleMask = NSHUDWindowMask | NSTitledWindowMask | NSUtilityWindowMask | NSClosableWindowMask;
|
||||||
else
|
else
|
||||||
@ -52,73 +52,63 @@
|
|||||||
// @"their passwords to change. You'll need to update your profile for that site with the new password."];
|
// @"their passwords to change. You'll need to update your profile for that site with the new password."];
|
||||||
// [moc saveToStore];
|
// [moc saveToStore];
|
||||||
// }];
|
// }];
|
||||||
[self handleUnloadedOrLocked];
|
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:YES];
|
||||||
} forKeyPath:@"key" options:NSKeyValueObservingOptionInitial context:nil];
|
} forKeyPath:@"key" options:NSKeyValueObservingOptionInitial context:nil];
|
||||||
[[NSNotificationCenter defaultCenter]
|
[[NSNotificationCenter defaultCenter]
|
||||||
addObserverForName:NSWindowDidBecomeKeyNotification object:self.window queue:nil usingBlock:^(NSNotification *note) {
|
addObserverForName:NSWindowDidBecomeKeyNotification object:self.window queue:nil usingBlock:^(NSNotification *note) {
|
||||||
NSLog(@"DidBecomeKey:\n%@", [NSThread callStackSymbols]);
|
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:NO];
|
||||||
[self checkLoadedAndUnlocked];
|
|
||||||
[self.siteField selectText:nil];
|
[self.siteField selectText:nil];
|
||||||
}];
|
}];
|
||||||
[[NSNotificationCenter defaultCenter]
|
[[NSNotificationCenter defaultCenter]
|
||||||
addObserverForName:NSWindowWillCloseNotification object:self.window queue:nil usingBlock:^(NSNotification *note) {
|
addObserverForName:NSWindowWillCloseNotification object:self.window queue:nil usingBlock:^(NSNotification *note) {
|
||||||
NSLog(@"WillClose:\n%@", [NSThread callStackSymbols]);
|
dispatch_async( dispatch_get_main_queue(), ^{
|
||||||
NSWindow *sheet = [self.window attachedSheet];
|
NSWindow *sheet = [self.window attachedSheet];
|
||||||
if (sheet)
|
if (sheet)
|
||||||
[NSApp endSheet:sheet];
|
[NSApp endSheet:sheet];
|
||||||
|
|
||||||
[NSApp hide:nil];
|
[NSApp hide:nil];
|
||||||
|
self.closing = NO;
|
||||||
|
} );
|
||||||
}];
|
}];
|
||||||
[[NSNotificationCenter defaultCenter]
|
[[NSNotificationCenter defaultCenter]
|
||||||
addObserverForName:MPSignedOutNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
|
addObserverForName:MPSignedOutNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
|
||||||
_activeElementOID = nil;
|
_activeElementOID = nil;
|
||||||
[self.siteField setStringValue:@""];
|
[self.siteField setStringValue:@""];
|
||||||
[self trySiteWithAction:NO];
|
[self trySiteWithAction:NO];
|
||||||
[self handleUnloadedOrLocked];
|
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:YES];
|
||||||
}];
|
}];
|
||||||
[[NSNotificationCenter defaultCenter]
|
[[NSNotificationCenter defaultCenter]
|
||||||
addObserverForName:USMStoreDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
|
addObserverForName:USMStoreDidChangeNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
|
||||||
[self checkLoadedAndUnlocked];
|
[self ensureLoadedAndUnlockedOrCloseIfLoggedOut:NO];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
[super windowDidLoad];
|
[super windowDidLoad];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)shouldCloseDocument {
|
|
||||||
NSLog(@"shouldCloseDocument:\n%@", [NSThread callStackSymbols]);
|
|
||||||
|
|
||||||
return [super shouldCloseDocument];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)close {
|
- (void)close {
|
||||||
NSLog(@"close:\n%@", [NSThread callStackSymbols]);
|
|
||||||
|
|
||||||
|
self.closing = YES;
|
||||||
[super close];
|
[super close];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)handleUnloadedOrLocked {
|
- (BOOL)ensureLoadedAndUnlockedOrCloseIfLoggedOut:(BOOL)closeIfLoggedOut {
|
||||||
|
|
||||||
if (!self.inProgress && ![MPMacAppDelegate get].key) {
|
if (![self ensureStoreLoaded])
|
||||||
MPUserEntity *activeUser = [MPMacAppDelegate get].activeUserForThread;
|
return NO;
|
||||||
if (activeUser && !activeUser.saveKey)
|
|
||||||
[self unlock];
|
if (self.closing || self.inProgress || !self.window.isKeyWindow)
|
||||||
else {
|
return NO;
|
||||||
NSLog(@"Closing: !inProgress && !key && (!activeUser || activeUser.saveKey)");
|
|
||||||
[self.window close];
|
return [self ensureUnlocked:closeIfLoggedOut];
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)checkLoadedAndUnlocked {
|
- (BOOL)ensureStoreLoaded {
|
||||||
|
|
||||||
if ([self waitUntilStoreLoaded] && !self.inProgress)
|
|
||||||
[self unlock];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)waitUntilStoreLoaded {
|
|
||||||
|
|
||||||
if ([MPMacAppDelegate managedObjectContextForThreadIfReady]) {
|
if ([MPMacAppDelegate managedObjectContextForThreadIfReady]) {
|
||||||
[NSApp endSheet:self.loadingDataAlert.window];
|
// Store loaded.
|
||||||
|
if (self.loadingDataAlert.window)
|
||||||
|
[NSApp endSheet:self.loadingDataAlert.window];
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,43 +120,57 @@
|
|||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)unlock {
|
- (BOOL)ensureUnlocked:(BOOL)closeIfLoggedOut {
|
||||||
|
|
||||||
[MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
__block BOOL unlocked = NO;
|
||||||
|
[MPMacAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *moc) {
|
||||||
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:moc];
|
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserInContext:moc];
|
||||||
NSString *userName = activeUser.name;
|
NSString *userName = activeUser.name;
|
||||||
if (!activeUser)
|
if (!activeUser) {
|
||||||
// No user to sign in with.
|
// No user to sign in with.
|
||||||
|
if (closeIfLoggedOut)
|
||||||
|
[self close];
|
||||||
return;
|
return;
|
||||||
if ([MPMacAppDelegate get].key)
|
}
|
||||||
// Already logged in.
|
if ([MPMacAppDelegate get].key) {
|
||||||
|
// Already logged in.
|
||||||
|
unlocked = YES;
|
||||||
return;
|
return;
|
||||||
if ([[MPMacAppDelegate get] signInAsUser:activeUser saveInContext:moc usingMasterPassword:nil])
|
}
|
||||||
// Load the key from the keychain.
|
if (activeUser.saveKey && closeIfLoggedOut) {
|
||||||
|
// App was locked, don't instantly unlock again.
|
||||||
|
[self close];
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
if ([[MPMacAppDelegate get] signInAsUser:activeUser saveInContext:moc usingMasterPassword:nil]) {
|
||||||
|
// Loaded the key from the keychain.
|
||||||
|
unlocked = YES;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (![MPMacAppDelegate get].key)
|
// Ask the user to set the key through his master password.
|
||||||
// Ask the user to set the key through his master password.
|
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||||
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
if ([MPMacAppDelegate get].key)
|
||||||
if ([MPMacAppDelegate get].key)
|
return;
|
||||||
return;
|
|
||||||
|
|
||||||
self.content = @"";
|
self.content = @"";
|
||||||
[self.siteField setStringValue:@""];
|
[self.siteField setStringValue:@""];
|
||||||
[self.tipField setStringValue:@""];
|
[self.tipField setStringValue:@""];
|
||||||
|
|
||||||
NSAlert *alert = [NSAlert alertWithMessageText:@"Master Password is locked."
|
NSAlert *alert = [NSAlert alertWithMessageText:@"Master Password is locked."
|
||||||
defaultButton:@"Unlock" alternateButton:@"Change" otherButton:@"Cancel"
|
defaultButton:@"Unlock" alternateButton:@"Change" otherButton:@"Cancel"
|
||||||
informativeTextWithFormat:@"The master password is required to unlock the application for:\n\n%@",
|
informativeTextWithFormat:@"The master password is required to unlock the application for:\n\n%@",
|
||||||
userName];
|
userName];
|
||||||
NSSecureTextField *passwordField = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
|
NSSecureTextField *passwordField = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
|
||||||
[alert setAccessoryView:passwordField];
|
[alert setAccessoryView:passwordField];
|
||||||
[alert layout];
|
[alert layout];
|
||||||
[passwordField becomeFirstResponder];
|
[passwordField becomeFirstResponder];
|
||||||
[alert beginSheetModalForWindow:self.window modalDelegate:self
|
[alert beginSheetModalForWindow:self.window modalDelegate:self
|
||||||
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertUnlockMP];
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertUnlockMP];
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
return unlocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)reload:(id)sender {
|
- (IBAction)reload:(id)sender {
|
||||||
@ -177,8 +181,7 @@
|
|||||||
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
|
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
|
||||||
|
|
||||||
if (contextInfo == MPAlertIncorrectMP) {
|
if (contextInfo == MPAlertIncorrectMP) {
|
||||||
NSLog(@"Closing: Incorrect MP, button: %ld", returnCode);
|
[self close];
|
||||||
[self.window close];
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (contextInfo == MPAlertUnlockMP) {
|
if (contextInfo == MPAlertUnlockMP) {
|
||||||
@ -209,9 +212,8 @@
|
|||||||
|
|
||||||
case NSAlertOtherReturn: {
|
case NSAlertOtherReturn: {
|
||||||
// "Cancel" button.
|
// "Cancel" button.
|
||||||
NSLog(@"Closing: Unlock MP, button: %ld", (long)returnCode);
|
[self close];
|
||||||
[self.window close];
|
break;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case NSAlertDefaultReturn: {
|
case NSAlertDefaultReturn: {
|
||||||
@ -228,7 +230,7 @@
|
|||||||
usingMasterPassword:password];
|
usingMasterPassword:password];
|
||||||
self.inProgress = NO;
|
self.inProgress = NO;
|
||||||
|
|
||||||
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
dispatch_async( dispatch_get_current_queue(), ^{
|
||||||
[self.progressView stopAnimation:nil];
|
[self.progressView stopAnimation:nil];
|
||||||
|
|
||||||
if (success)
|
if (success)
|
||||||
@ -239,7 +241,7 @@
|
|||||||
}]] beginSheetModalForWindow:self.window modalDelegate:self
|
}]] beginSheetModalForWindow:self.window modalDelegate:self
|
||||||
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertIncorrectMP];
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertIncorrectMP];
|
||||||
}
|
}
|
||||||
}];
|
} );
|
||||||
}];
|
}];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -307,8 +309,7 @@
|
|||||||
- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector {
|
- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector {
|
||||||
|
|
||||||
if (commandSelector == @selector(cancel:)) { // Escape without completion.
|
if (commandSelector == @selector(cancel:)) { // Escape without completion.
|
||||||
NSLog(@"Closing: ESC without completion");
|
[self close];
|
||||||
[self.window close];
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
if ((self.siteFieldPreventCompletion = [NSStringFromSelector( commandSelector ) hasPrefix:@"delete"])) { // Backspace any time.
|
if ((self.siteFieldPreventCompletion = [NSStringFromSelector( commandSelector ) hasPrefix:@"delete"])) { // Backspace any time.
|
||||||
@ -399,7 +400,6 @@
|
|||||||
if (!content)
|
if (!content)
|
||||||
content = @"";
|
content = @"";
|
||||||
|
|
||||||
dbg(@"name: %@, action: %d", siteName, doAction);
|
|
||||||
if (doAction) {
|
if (doAction) {
|
||||||
if ([content length]) {
|
if ([content length]) {
|
||||||
// Performing action while content is available. Copy it.
|
// Performing action while content is available. Copy it.
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
|
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
|
||||||
BuildableName = "MasterPassword.app"
|
BuildableName = "Master Password.app"
|
||||||
BlueprintName = "MasterPassword"
|
BlueprintName = "MasterPassword"
|
||||||
ReferencedContainer = "container:MasterPassword-Mac.xcodeproj">
|
ReferencedContainer = "container:MasterPassword-Mac.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
@ -43,7 +43,7 @@
|
|||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
|
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
|
||||||
BuildableName = "MasterPassword.app"
|
BuildableName = "Master Password.app"
|
||||||
BlueprintName = "MasterPassword"
|
BlueprintName = "MasterPassword"
|
||||||
ReferencedContainer = "container:MasterPassword-Mac.xcodeproj">
|
ReferencedContainer = "container:MasterPassword-Mac.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
|
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
|
||||||
BuildableName = "MasterPassword.app"
|
BuildableName = "Master Password.app"
|
||||||
BlueprintName = "MasterPassword"
|
BlueprintName = "MasterPassword"
|
||||||
ReferencedContainer = "container:MasterPassword-Mac.xcodeproj">
|
ReferencedContainer = "container:MasterPassword-Mac.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
@ -43,17 +43,11 @@
|
|||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
|
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
|
||||||
BuildableName = "MasterPassword.app"
|
BuildableName = "Master Password.app"
|
||||||
BlueprintName = "MasterPassword"
|
BlueprintName = "MasterPassword"
|
||||||
ReferencedContainer = "container:MasterPassword-Mac.xcodeproj">
|
ReferencedContainer = "container:MasterPassword-Mac.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
||||||
<CommandLineArguments>
|
|
||||||
<CommandLineArgument
|
|
||||||
argument = "-com.apple.coredata.ubiquity.logLevel 3"
|
|
||||||
isEnabled = "NO">
|
|
||||||
</CommandLineArgument>
|
|
||||||
</CommandLineArguments>
|
|
||||||
<EnvironmentVariables>
|
<EnvironmentVariables>
|
||||||
<EnvironmentVariable
|
<EnvironmentVariable
|
||||||
key = "CA_DEBUG_TRANSACTIONS"
|
key = "CA_DEBUG_TRANSACTIONS"
|
||||||
|
Loading…
Reference in New Issue
Block a user