Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Threema/ThreemaFramework/Business/   (Social Medium ©)  Datei vom 26.9.2026 mit Größe 9 kB image not shown  

Quelle  LicenseStore.m   Sprache: Unknown

 

Spracherkennung für: .m vermutete Sprache: Abap {ABAP[36] Lisp[33] Masm[33]} [Methode: maximale Elemente, drei Dimensionen]

#import "LicenseStore.h"
#import "BundleUtil.h"
#import "ServerAPIConnector.h"
#import "ThreemaUtilityObjC.h"
#import "ThreemaError.h"
#import "AppGroup.h"
#import "MyIdentityStore.h"
#import "NaClCrypto.h"
#import "NSString+Hex.h"
#import "ThreemaFramework/ThreemaFramework-Swift.h"
@import Keychain;

#ifdef DEBUG
  static const DDLogLevel ddLogLevel = DDLogLevelAll;
#else
  static const DDLogLevel ddLogLevel = DDLogLevelNotice;
#endif

#define WORK_APP_ID @"ch.threema.work." // Prefix for ch.threema.work.iapp and ch.threema.work.red.iapp
#define ONPREM_APP_ID @"ch.threema.onprem."

#define LICENSE_CHECK_INTERVAL_S 6*60*60
#define LICENSE_OFFLINE_INTERVAL_S 24*60*60
#define DEVICE_ID_LENGTH 16

@interface LicenseStore ()

@property BOOL didCheckLicense;
@property dispatch_semaphore_t sema;
@property NSString *internalDeviceID;

@end

@implementation LicenseStore

@synthesize licenseUsername = _licenseUsername;
@synthesize licensePassword = _licensePassword;
@synthesize licenseDeviceID;
@synthesize onPremConfigUrl = _onPremConfigUrl;

@synthesize internalDeviceID;

@synthesize error;
@synthesize errorMessage;

+ (nonnull instancetype)sharedLicenseStore {
    static LicenseStore *instance;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [LicenseStore new];
    });

    return instance;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        _didCheckLicense = NO;
        
        _sema = dispatch_semaphore_create(1);
    }
    return self;
}

- (BOOL)isWithinCheckInterval {
    NSDate *lastCheck = [MyIdentityStore sharedMyIdentityStore].licenseLastCheck;
    if (lastCheck == nil) {
        return NO;
    }
    
    NSTimeInterval time = [[NSDate date] timeIntervalSinceDate:lastCheck];
    if (time > LICENSE_CHECK_INTERVAL_S) {
        return NO;
    }
    
    return YES;
}

- (BOOL)isWithinOfflineInterval {
    NSDate *lastCheck = [MyIdentityStore sharedMyIdentityStore].licenseLastCheck;
    if (lastCheck == nil) {
        return NO;
    }
    
    NSTimeInterval time = [[NSDate date] timeIntervalSinceDate:lastCheck];
    if (time > LICENSE_OFFLINE_INTERVAL_S) {
        return NO;
    }
    
    return YES;
}


- (BOOL)isValid {
    if (TargetManagerObjC.isBusinessApp) {
        if (_didCheckLicense) {
            if ([self isWithinCheckInterval] == NO) {
                // force fresh license check
                _didCheckLicense = NO;
                DDLogNotice(@"License Check: force fresh license check");
                return NO;
            }
            return YES;
        } else if (([AppGroup getCurrentType] == AppGroupTypeNotificationExtension || [AppGroup getCurrentType] == AppGroupTypeShareExtension) && [self isWithinOfflineInterval]) {
            // keep notification or share extension valid for one day
            return YES;
        }
        else {
            // force license check on every app start
            DDLogNotice(@"License Check: it's not valid");
            return NO;
        }
    }
    
    return YES;
}

- (void)performLicenseCheckWithCompletion:(nonnull void(^)(BOOL success))onCompletion {
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        dispatch_semaphore_wait(_sema, DISPATCH_TIME_FOREVER);
        
        if (_didCheckLicense) {
            dispatch_semaphore_signal(_sema);
            onCompletion(YES);
            return;
        }
        
        if (_licenseUsername.length < 1 || _licensePassword.length < 1) {
            dispatch_semaphore_signal(_sema);
            
            errorMessage = @"License username/password too short";
            onCompletion(NO);
            return;
        }
        
        NSString *appId = [BundleUtil mainBundle].bundleIdentifier;
        NSString *version = ThreemaUtility.clientVersion;
        
        ServerAPIConnector *connector = [[ServerAPIConnector alloc] init];
        [connector validateLicenseUsername:_licenseUsername password:_licensePassword appId:appId version:version deviceId:[self licenseDeviceID] onCompletion:^(BOOL success, NSDictionary *info) {
            error = nil;
            errorMessage = nil;
            if (success) {
                [MyIdentityStore sharedMyIdentityStore].licenseLastCheck = [NSDate date];
                _didCheckLicense = YES;
            } else {
                [MyIdentityStore sharedMyIdentityStore].licenseLastCheck = nil;
                _didCheckLicense = NO;
                errorMessage = info[@"error"];
            }
            MDMSetup *mdmSetup = [MDMSetup new];
            [mdmSetup applyCompanyMDMWithCachedThreemaMDMSendForce:false];
            dispatch_semaphore_signal(_sema);
            onCompletion(success);
        } onError:^(NSError *validationError) {
            errorMessage = validationError.localizedDescription;
            error = validationError;
            
            if ([error.domain hasPrefix:@"NSURL"] == NO && error.code != 256) {
                // Remove licenseLastCheck. If notification extension will be started, it will not process the messages
                [MyIdentityStore sharedMyIdentityStore].licenseLastCheck = nil;
                _didCheckLicense = NO;
            }
            
            dispatch_semaphore_signal(_sema);
            onCompletion(NO);
        }];
    });
}

- (void)performUpdateWorkInfoForce:(BOOL)force {
    // Only send the update work info when there is a valid license username and a valid threema id
    if (!TargetManagerObjC.isBusinessApp || _licenseUsername.length < 1 || !AppSetup.isCompleted) {
        return;
    }
        
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        ServerAPIConnector *connector = [[ServerAPIConnector alloc] init];
        [connector updateWorkInfoForStore:[MyIdentityStore sharedMyIdentityStore] licenseUsername:_licenseUsername password:_licensePassword force:force onCompletion:^(BOOL sent) {
            if (sent) {
                DDLogNotice(@"Work info update completed (sent, %@)", [AppGroup getCurrentTypeString]);
            } else {
                DDLogNotice(@"Work info update completed without changes (not sent, %@)", [AppGroup getCurrentTypeString]);
            }
        } onError:^(NSError *error) {
            DDLogError(@"Work info update failed (%@): %@", [AppGroup getCurrentTypeString], error);
        }];
    });
}

- (void)performUpdateWorkInfo {
    [self performUpdateWorkInfoForce:NO];
}

- (void)setLicenseUsername:(NSString *)licenseUsername {
    if ([_licenseUsername isEqualToString:licenseUsername] == NO) {
        _licenseUsername = licenseUsername;
        _didCheckLicense = NO;
    }
}

- (NSString *)licenseUsername {
    return _licenseUsername;
}

- (void)setLicensePassword:(NSString *)licensePassword {
    if ([_licensePassword isEqualToString:licensePassword] == NO) {
        _licensePassword = licensePassword;
        _didCheckLicense = NO;
    }
}

- (NSString *)licensePassword {
    return _licensePassword;
}

- (BOOL)validCustomOnPremConfigUrlWithPredefinedUrl:(NSString *)onPremConfigUrl {
    if ([TargetManagerObjC isCustomOnPrem]) {
        NSString *formattedOnPremConfigUrl = [self formatOnPremConfigUrl:onPremConfigUrl];
        
        NSString *presetOppfUrl = [BundleUtil objectForInfoDictionaryKey:@"PresetOppfUrl"];
        if (presetOppfUrl != nil) {
            return [[self formatOnPremConfigUrl:presetOppfUrl] isEqualToString:formattedOnPremConfigUrl];
        }
        else {
            return YES;
        }
    }
    
    return YES;
}

- (void)setOnPremConfigUrl:(NSString *)onPremConfigUrl {
    NSString *formattedOnPremConfigUrl = [self formatOnPremConfigUrl:onPremConfigUrl];
    
    // Change it only if the final url was changed. Otherwise it will be in a endless loop when the url is set in the company mdm
    if ([_onPremConfigUrl isEqualToString:formattedOnPremConfigUrl] == NO) {
        if ([self validCustomOnPremConfigUrlWithPredefinedUrl:formattedOnPremConfigUrl]) {
            _onPremConfigUrl = formattedOnPremConfigUrl;
            _didCheckLicense = NO;
        } else {
            // Show Error
        }
    }
}

- (NSString *)formatOnPremConfigUrl:(NSString *)onPremConfigUrl {
    NSString *formattedOnPremConfigUrl = onPremConfigUrl;
    // Automatically expand hostnames to default provisioning URL
    if (![formattedOnPremConfigUrl hasPrefix:@"https://"]) {
        formattedOnPremConfigUrl = [NSString stringWithFormat:@"https://%@", formattedOnPremConfigUrl];
    }
    else if ([formattedOnPremConfigUrl hasPrefix:@"https://https://"]) {
        formattedOnPremConfigUrl= [formattedOnPremConfigUrl substringFromIndex:8];
    }
    
    NSString *check = [formattedOnPremConfigUrl substringFromIndex:8];
    if (![check hasSuffix:@".oppf"]) {
        if ([check hasSuffix:@"/"]) {
            formattedOnPremConfigUrl = [NSString stringWithFormat:@"%@prov/config.oppf", formattedOnPremConfigUrl];
        }
        else {
            formattedOnPremConfigUrl = [NSString stringWithFormat:@"%@/prov/config.oppf", formattedOnPremConfigUrl];
        }
    }
    return formattedOnPremConfigUrl;
}

- (NSString *)onPremConfigUrl {
    return _onPremConfigUrl;
}

- (void)deleteLicense {
    _didCheckLicense = NO;
    _licenseUsername = nil;
    _licensePassword = nil;
    _onPremConfigUrl = nil;

    NSError *error = nil;

    KeychainManager *keychain = [[BusinessInjector ui] keychainManagerObjC];
    [keychain deleteLicenseAndReturnError:&error];
    if (error) {
        DDLogError(@"Couldn't delete license in Keychain: %@", [error localizedDescription]);
    }
}

#pragma mark - private

- (NSString *)licenseDeviceID {
    if (internalDeviceID == nil) {
        internalDeviceID = [NSString stringWithHexData:[[NaClCrypto sharedCrypto] randomBytes:DEVICE_ID_LENGTH]];

    }
    return internalDeviceID;
}

- (void)setLicenseDeviceID:(NSString *)newLicenseDeviceID {
    if ([newLicenseDeviceID decodeHex].length == DEVICE_ID_LENGTH) {
        internalDeviceID = newLicenseDeviceID;
    }
    else {
        internalDeviceID = nil;
    }
}

@end

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet am  2026-11-04) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.