web-dev-qa-db-ja.com

プロビジョニングプロファイルが開発または配布用であることをプログラムで検出する方法

特定のプロビジョニングプロファイルが開発プロファイルであるか、配布(アドホックまたはアプリストア)プロファイルであるかを検出したいと思います。私はこれを純粋にプログラムで行う必要があります。

アドホックとアプリストアを検出する方法はすでに理解しています。そして、特に開発と配布に興味があります。

各タイプのプロファイルの内部のplistを調べましたが、識別可能な違いを見つけることができません(security cms -D -i #{@profilePath}を介して)。また、openssl apiを調べて、これを証明書の操作に使用しています。

これは、カスタムxcode自動ビルドシステム用です。ビルド前の検証の一環として、指定したプロファイルが開発用ではないことを確認する必要があります。

これも可能ですか?もしそうなら、どうすればプログラムで2つを区別できますか?

アイデアをよろしくお願いします!

27
Alfie Hanssen

これは、私が自分のビルドシステムの1つで、ほぼ同じ目的で取り組んだことでした...当時の「iPhone開発者プログラム」の1日目に戻ってみましょう。当時、コミュニティの周りにいた場合は、ツールチェーンが...今日よりも友好的ではなかったことを覚えているかもしれません。

AppStoreまたはAdHocビルド用にビルドする場合は、この奇妙なentitlements.plistファイルを作成してから、XMLのblobをそのファイルの本文に貼り付ける必要がありました。次にビルドを実行すると、その時点で魔法のように見えたものが発生し、そのファイルの存在がビルドを機能させ、手動でIPAを構築し、通常どおりビジネスを続行できるようにしました。 SDKの初期の頃よりも数年年上で、うまくいけば少し賢くなったので、魔法のXMLブロブは実際にはそれほど魔法ではなかったことがわかりました-「get-task-allow」キーは、バイナリが他のプロセス(おそらくデバッガなど)がバイナリに接続できるようにするかどうかを示す設定です。開発プロビジョニングプロファイルを使用してアプリに署名する場合、このキーは「true」に設定されます(したがって、LLDBがアプリに接続して対話できるようになります)...そして当然、ディストリビューションプロビジョニングプロファイルを使用してアプリに署名する場合、このキーが設定されます'false'に。

Appleは、プロビジョニングプロファイルからのXML(および拡張機能としてエンタイトルメント)の読み取りについて、 テクニカルノートTN225 でいくつかの更新を提供しました。

セキュリティcms-D -i /path/to/the.app/embedded.mobileprovision

これにより、プロビジョニングプロファイルにXMLが返されます。そこから、「get-task-allow」のキーと値のペアを解析し、その値を使用して、プロビジョニングプロファイルが開発か配布かを判断できます。

手がかりを得るためにプロファイルをスニッフィングする必要がないように、直接それを教えてくれるツールがあればいいのにと思いますが、同時に、少なくとも、回り道ではありますが、信頼性の高い方法があります。実行して使用できないビルドを作成する前に、その区別をしてください。

幸運を祈ります。さらに詳しい説明が必要な場合やその他の質問がある場合はお知らせください。

19
Bryan Musial

Toomのコードのより簡潔で効率的なバージョンを作成しました。

このようなコードスニペットをGistで維持します。ここで、より最新のバージョンを見つけることができます: https://Gist.github.com/steipete/7668246

static BOOL PSPDFIsDevelopmentBuild(void) {
#if TARGET_IPHONE_SIMULATOR
return YES;
#else
static BOOL isDevelopment = NO;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // There is no provisioning profile in AppStore Apps.
    NSData *data = [NSData dataWithContentsOfFile:[NSBundle.mainBundle pathForResource:@"embedded" ofType:@"mobileprovision"]];
    if (data) {
        const char *bytes = [data bytes];
        NSMutableString *profile = [[NSMutableString alloc] initWithCapacity:data.length];
        for (NSUInteger i = 0; i < data.length; i++) {
            [profile appendFormat:@"%c", bytes[i]];
        }
        // Look for debug value, if detected we're a development build.
        NSString *cleared = [[profile componentsSeparatedByCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet] componentsJoinedByString:@""];
        isDevelopment = [cleared rangeOfString:@"<key>get-task-allow</key><true/>"].length > 0;
    }
});
return isDevelopment;
#endif
}
21
steipete

Bryan Musialのすばらしい回答に基づいて、実行時にアプリケーションから直接「get-task-allow」をチェックできるコードをいくつか作成しました。私の場合、このブール値を使用してデバッグアプリにのみログインしています:

+ (BOOL)isDevelopmentApp
{
    // Special case of simulator
    if (isSimulator)
    {
        return YES;
    }

    // There is no provisioning profile in AppStore Apps
    NSString *profilePath = [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"];

    // Check provisioning profile existence
    if (profilePath)
    {
        // Get hex representation
        NSData *profileData = [NSData dataWithContentsOfFile:profilePath];
        NSString *profileString = [NSString stringWithFormat:@"%@", profileData];

        // Remove brackets at beginning and end
        profileString = [profileString stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""];
        profileString = [profileString stringByReplacingCharactersInRange:NSMakeRange(profileString.length - 1, 1) withString:@""];

        // Remove spaces
        profileString = [profileString stringByReplacingOccurrencesOfString:@" " withString:@""];

        // Convert hex values to readable characters
        NSMutableString *profileText = [NSMutableString new];
        for (int i = 0; i < profileString.length; i += 2)
        {
            NSString *hexChar = [profileString substringWithRange:NSMakeRange(i, 2)];
            int value = 0;
            sscanf([hexChar cStringUsingEncoding:NSASCIIStringEncoding], "%x", &value);
            [profileText appendFormat:@"%c", (char)value];
        }

        // Remove whitespaces and new lines characters
        NSArray *profileWords = [profileText componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
        NSString *profileClearText = [profileWords componentsJoinedByString:@""];

        // Look for debug value
        NSRange debugRange = [profileClearText rangeOfString:@"<key>get-task-allow</key><true/>"];
        if (debugRange.location != NSNotFound)
        {
            return YES;
        }
    }

    // Return NO by default to avoid security leaks
    return NO;
}
9
Toom

@steipeteの回答に基づいたSwift 3のバージョンは次のとおりです。

static func isDevelopmentProvisioningProfile() -> Bool {
#if IOS_SIMULATOR
    return true
#else
    // there will be no provisioning profile in AppStore Apps
    guard let fileName = Bundle.main.path(forResource: "embedded", ofType: "mobileprovision") else {
        return false
    }

    let fileURL = URL(fileURLWithPath: fileName)
    // the documentation says this file is in UTF-8, but that failed
    // on my machine. ASCII encoding worked ¯\_(ツ)_/¯
    guard let data = try? String(contentsOf: fileURL, encoding: .ascii) else {
        return false
    }

    let cleared: String = data.components(separatedBy: .whitespacesAndNewlines).joined()
    return cleared.contains("<key>get-task-allow</key><true/>")
#endif
}

興味があれば、get-task-allow is デバッガーやそのような他のプロセスを接続できるかどうかを判断するためにビルドが使用するフラグ -したがって、開発ビルドであるかどうかは非常に正確です。

6
Hannele