Skip to content

Instantly share code, notes, and snippets.

@mironal
Created February 2, 2024 08:03
Show Gist options
  • Save mironal/9169633fb09c06c2f8f781ebe01644b7 to your computer and use it in GitHub Desktop.
Save mironal/9169633fb09c06c2f8f781ebe01644b7 to your computer and use it in GitHub Desktop.
Apple Privacy Manifest: Describing use of required reason API

Run this script in Describing use of required reason API.

let element = document.querySelector(".content > h3")
const results = []
do {
    if (element.nodeName === "H3") {
        const title = element.textContent
        results.push({ APIType: title })
    } else if (element.nodeName === "P" && element.textContent.includes("NSPrivacyAccessedAPICategory")) {
        const category = element.textContent.match(/NSPrivacyAccessedAPICategory\w+/)[0]
        // resultsの最後に入れる
        results[results.length - 1] = { ...results[results.length - 1], NSPrivacyAccessedAPIType: category }
    } else if (element.nodeName === "UL") {
        const items = element.querySelectorAll("li")
        const apis = Array.from(items).map(item => item.textContent)
        results[results.length - 1] = { ...results[results.length - 1], apis }
    } else if (element.nodeName === "DL") {
        // NSPrivacyAccessedAPITypeReasons
        // dt: id, dd: descriptionがあるのでreason: ({ id: description }[])の形にする
        const items = element.querySelectorAll("dt")
        const reasons = Array.from(items).map(item => {
            const id = item.textContent
            const description = item.nextElementSibling.textContent
            return { id, description }
        })
        results[results.length - 1] = { ...results[results.length - 1], reasons }
    }

    element = element.nextElementSibling
} while (element)
copy(results)
[
{
“APIType”: “File timestamp APIs”,
“NSPrivacyAccessedAPIType”: “NSPrivacyAccessedAPICategoryFileTimestamp”,
“apis”: [
“creationDate”,
“modificationDate”,
“fileModificationDate”,
“contentModificationDateKey”,
“creationDateKey”,
“getattrlist(::::_:)“,
“getattrlistbulk(::::_:)“,
“fgetattrlist(::::_:)“,
“stat”,
“fstat(::)“,
“fstatat(::::)“,
“lstat(::)“,
“getattrlistat(::::::)”
],
“reasons”: [
{
“id”: “DDA9.1",
“description”: “Declare this reason to display file timestamps to the person using the device.Information accessed for this reason, or any derived information, may not be sent off-device.”
},
{
“id”: “C617.1",
“description”: “Declare this reason to access the timestamps, size, or other metadata of files inside the app container, app group container, or the app’s CloudKit container.”
},
{
“id”: “3B52.1",
“description”: “Declare this reason to access the timestamps, size, or other metadata of files or directories that the user specifically granted access to, such as using a document picker view controller.”
},
{
“id”: “0A2A.1",
“description”: “Declare this reason if your third-party SDK is providing a wrapper function around file timestamp API(s) for the app to use, and you only access the file timestamp APIs when the app calls your wrapper function. This reason may only be declared by third-party SDKs. This reason may not be declared if your third-party SDK was created primarily to wrap required reason API(s). Information accessed for this reason, or any derived information, may not be used for your third-party SDK’s own purposes or sent off-device by your third-party SDK.”
}
]
},
{
“APIType”: “System boot time APIs”,
“NSPrivacyAccessedAPIType”: “NSPrivacyAccessedAPICategorySystemBootTime”,
“apis”: [
“systemUptime”,
“mach_absolute_time()”
],
“reasons”: [
{
“id”: “35F9.1",
“description”: “Declare this reason to access the system boot time in order to measure the amount of time that has elapsed between events that occurred within the app or to perform calculations to enable timers.Information accessed for this reason, or any derived information, may not be sent off-device. There is an exception for information about the amount of time that has elapsed between events that occurred within the app, which may be sent off-device.”
}
]
},
{
“APIType”: “Disk space APIs”,
“NSPrivacyAccessedAPIType”: “NSPrivacyAccessedAPICategoryDiskSpace”,
“apis”: [
“volumeAvailableCapacityKey”,
“volumeAvailableCapacityForImportantUsageKey”,
“volumeAvailableCapacityForOpportunisticUsageKey”,
“volumeTotalCapacityKey”,
“systemFreeSize”,
“systemSize”,
“statfs(::)“,
“statvfs(::)“,
“fstatfs(::)“,
“fstatvfs(::)“,
“getattrlist(::::_:)“,
“fgetattrlist(::::_:)“,
“getattrlistat(::::::)”
],
“reasons”: [
{
“id”: “85F4.1",
“description”: “Declare this reason to display disk space information to the person using the device. Disk space may be displayed in units of information (such as bytes) or units of time combined with a media type (such as minutes of HD video).Information accessed for this reason, or any derived information, may not be sent off-device. There is an exception that allows the app to send disk space information over the local network to another device operated by the same person only for the purpose of displaying disk space information on that device; this exception only applies if the user has provided explicit permission to send disk space information, and the information may not be sent over the Internet.”
},
{
“id”: “E174.1",
“description”: “Declare this reason to check whether there is sufficient disk space to write files, or to check whether the disk space is low so that the app can delete files when the disk space is low. The app must behave differently based on disk space in a way that is observable to users.Information accessed for this reason, or any derived information, may not be sent off-device. There is an exception that allows the app to avoid downloading files from a server when disk space is insufficient.”
},
{
“id”: “7D9E.1",
“description”: “Declare this reason to include disk space information in an optional bug report that the person using the device chooses to submit. The disk space information must be prominently displayed to the person as part of the report.Information accessed for this reason, or any derived information, may be sent off-device only after the user affirmatively chooses to submit the specific bug report including disk space information, and only for the purpose of investigating or responding to the bug report.”
}
]
},
{
“APIType”: “Active keyboard APIs”,
“NSPrivacyAccessedAPIType”: “NSPrivacyAccessedAPICategoryActiveKeyboards”,
“apis”: [
“activeInputModes”
],
“reasons”: [
{
“id”: “3EC4.1”,
“description”: “Declare this reason if your app is a custom keyboard app, and you access this API category to determine the keyboards that are active on the device.Providing a systemwide custom keyboard to the user must be the primary functionality of the app.Information accessed for this reason, or any derived information, may not be sent off-device.”
},
{
“id”: “54BD.1”,
“description”: “Declare this reason to access active keyboard information to present the correct customized user interface to the person using the device. The app must have text fields for entering or editing text and must behave differently based on active keyboards in a way that is observable to users.Information accessed for this reason, or any derived information, may not be sent off-device.”
}
]
},
{
“APIType”: “User defaults APIs”,
“NSPrivacyAccessedAPIType”: “NSPrivacyAccessedAPICategoryUserDefaults”,
“apis”: [
“UserDefaults”
],
“reasons”: [
{
“id”: “CA92.1",
“description”: “Declare this reason to access user defaults to read and write information that is only accessible to the app itself.This reason does not permit reading information that was written by other apps or the system, or writing information that can be accessed by other apps.”
},
{
“id”: “1C8F.1",
“description”: “Declare this reason to access user defaults to read and write information that is only accessible to the apps, app extensions, and App Clips that are members of the same App Group as the app itself.This reason does not permit reading information that was written by apps, app extensions, or App Clips outside the same App Group or by the system. This reason also does not permit writing information that can be accessed by apps, app extensions, or App Clips outside the same App Group.”
},
{
“id”: “C56D.1",
“description”: “Declare this reason if your third-party SDK is providing a wrapper function around user defaults API(s) for the app to use, and you only access the user defaults APIs when the app calls your wrapper function. This reason may only be declared by third-party SDKs. This reason may not be declared if your third-party SDK was created primarily to wrap required reason API(s). Information accessed for this reason, or any derived information, may not be used for your third-party SDK’s own purposes or sent off-device by your third-party SDK.”
},
{
“id”: “AC6B.1",
“description”: “Declare this reason to access user defaults to read the com.apple.configuration.managed key to retrieve the managed app configuration set by MDM, or to set the com.apple.feedback.managed key to store feedback information to be queried over MDM, as described in the Apple Mobile Device Management Protocol Reference documentation.”
}
]
}
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment