Skip to content

Privacy Manifest #546

Description

@sashabaranov

From Apple docs:

Starting in spring 2024, you must include the privacy manifest for any SDK listed below when you submit new apps in App Store Connect that include those SDKs, or when you submit an app update that adds one of the listed SDKs as part of the update. Signatures are also required in these cases where the listed SDKs are used as binary dependencies.

Could you please add a privacy manifest for this library?

Activity

  1. grantneufeld commented on Dec 13, 2023

    @grantneufeld

    I don’t know that a privacy manifest is needed for Swifter. I don’t think the library hits any privacy issues (unlike those on Apple’s list of SDKs requiring privacy manifests; linked in the original comment).

    SDKs with privacy issues (therefore requiring a privacy manifest) are those that take any user data, or define any tokens tied to a user, or track users’ activity (such as website visits). Swifter does none of that. Our apps using Swifter may or may not hit privacy issues, depending on what we have them do, but Swifter itself does not (as far as I’m aware).

  2. haniewais commented on Mar 8, 2024

    @haniewais

    According to the apple docs, specifically the Reason API:

    Some APIs that your app uses to deliver its core functionality — in code you write or included in a third-party SDK — have the potential of being misused to access device signals to try to identify the device or user, also known as fingerprinting. Regardless of whether a user gives your app permission to track, fingerprinting is not allowed. Describe the reasons your app or third-party SDK on iOS, iPadOS, tvOS, visionOS, or watchOS uses these APIs, and check that your app or third-party SDK only uses the APIs for the expected reasons.

    Swifter does use the stat timestamp system api here:

    return stat.st_mode & S_IFMT == S_IFDIR

    I believe this requires a privacy manifest file from my understanding which will bubble up to the main project's privacy manifest.

  3. grantneufeld commented on Mar 11, 2024

    @grantneufeld

    The function with that code is:

    public func directory() throws -> Bool {
        return try self.withStat {
            if let stat = $0 {
                return stat.st_mode & S_IFMT == S_IFDIR
            }
            return false
        }
    }

    Which calls through to:

    private func withStat<T>(_ closure: ((stat?) throws -> T)) throws -> T {
        return try self.withCString({
            var statBuffer = stat()
            if stat($0, &statBuffer) == 0 {
                return try closure(statBuffer)
            }
            if errno == ENOENT {
                return try closure(nil)
            }
            throw FileError.error(errno)
        })
    }

    The directory() function seems to only be used in one place, Sources/Files.swift: directoryBrowser(). It’s not entirely clear to me, but that one usage seems to be just checking if the filepath is a readable directory?

    public func directoryBrowser(_ dir: String) -> ((HttpRequest) -> HttpResponse) {
        return { request in
            guard let (_, value) = request.params.first else {
                return HttpResponse.notFound
            }
            let filePath = dir + String.pathSeparator + value
            do {
                guard try filePath.exists() else {
                    return .notFound
                }
                if try filePath.directory() { // ⬅️ ⭐️ CALL TO directory()
                    var files = try filePath.files()
                    files.sort(by: {$0.lowercased() < $1.lowercased()})
                    return scopes {
                        html {
                            body {
                                table(files) { file in
                                    tr {
                                        td {
                                            a {
                                                href = request.path + "/" + file
                                                inner = file
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        }(request)
                } else {
                    guard let file = try? filePath.openForReading() else {
                        return .notFound
                    }
                    return .raw(200, "OK", [:], { writer in
                        try? writer.write(file)
                        file.close()
                    })
                }
            } catch {
                return HttpResponse.internalServerError
            }
        }
    }

    If I am correct that it’s just checking that the directory is readable, then perhaps an alternative approach may be taken that doesn’t call the stat function that seems to be triggering Apple’s privacy restrictions?

  4. haniewais commented on Mar 12, 2024

    @haniewais

    Good stuff, I believe it would easier to just add the privacy manifest and keep the stat call, not sure how else to check if the directory exists without a system API call.

  5. haniewais commented on Mar 13, 2024

    @haniewais

    I attempted to create a PR: #550

  6. EvanMasterson commented on Apr 24, 2024

    @EvanMasterson

    +1 on this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions