-
Notifications
You must be signed in to change notification settings - Fork 233
OpenAPI: Reuse generated AppSettings model in the public API layer #4159
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,83 +5,41 @@ | |
| import CoreServices | ||
| import Foundation | ||
|
|
||
| /// A type representing the app settings. | ||
| public struct AppSettings: Sendable { | ||
| /// The name of the app. | ||
| public let name: String | ||
| /// The the file uploading configuration. | ||
| public let fileUploadConfig: UploadConfig | ||
| /// The the image uploading configuration. | ||
| public let imageUploadConfig: UploadConfig | ||
| /// A boolean value determining if auto translation is enabled. | ||
| public let autoTranslationEnabled: Bool | ||
| /// A boolean value determining if async url enrichment is enabled. | ||
| public let asyncUrlEnrichEnabled: Bool | ||
|
|
||
| public struct UploadConfig: Sendable { | ||
| /// The allowed file extensions. | ||
| public let allowedFileExtensions: [String] | ||
| /// The blocked file extensions. | ||
| public let blockedFileExtensions: [String] | ||
| /// The allowed mime types. | ||
| public let allowedMimeTypes: [String] | ||
| /// The blocked mime types. | ||
| public let blockedMimeTypes: [String] | ||
| /// The file size limit allowed in Bytes. | ||
| /// This value is configurable from Stream's Dashboard App Settings. | ||
| public let sizeLimitInBytes: Int64? | ||
| } | ||
| } | ||
|
|
||
| // MARK: - Response -> Model | ||
|
|
||
| extension GetApplicationResponse { | ||
| func asModel() -> AppSettings { | ||
| .init( | ||
| name: app.name, | ||
| fileUploadConfig: app.fileUploadConfig.asModel(), | ||
| imageUploadConfig: app.imageUploadConfig.asModel(), | ||
| autoTranslationEnabled: app.autoTranslationEnabled, | ||
| asyncUrlEnrichEnabled: app.asyncUrlEnrichEnabled | ||
| ) | ||
| } | ||
| extension AppSettings { | ||
| /// The upload configuration. | ||
| public typealias UploadConfig = StreamChat.UploadConfig | ||
| } | ||
|
|
||
| extension FileUploadConfig { | ||
| func asModel() -> AppSettings.UploadConfig { | ||
| .init( | ||
| allowedFileExtensions: allowedFileExtensions, | ||
| blockedFileExtensions: blockedFileExtensions, | ||
| allowedMimeTypes: allowedMimeTypes, | ||
| blockedMimeTypes: blockedMimeTypes, | ||
| sizeLimitInBytes: Int64(sizeLimit) | ||
| ) | ||
| } | ||
| extension AppSettings.UploadConfig { | ||
| /// The file size limit allowed in Bytes. | ||
| /// This value is configurable from Stream's Dashboard App Settings. | ||
| @available(*, deprecated, renamed: "sizeLimit") | ||
| public var sizeLimitInBytes: Int64? { Int64(sizeLimit) } | ||
| } | ||
|
|
||
| // MARK: - Validation | ||
|
|
||
| extension AppSettings.UploadConfig { | ||
| // MARK: - UTI Validation | ||
|
|
||
| /// Returns an array of allowed UTI identifiers based on allowed mime types and file extensions. | ||
| public var allowedUTITypes: [String] { | ||
| allowedMimeTypes.compactMap { $0.utiType(mime: true) } + | ||
| allowedFileExtensions.compactMap { $0.utiType(mime: false) } | ||
| } | ||
|
|
||
| /// Returns an array of blocked UTI identifiers based on allowed mime types and file extensions. | ||
| public var blockedUTITypes: [String] { | ||
| blockedMimeTypes.compactMap { $0.utiType(mime: true) } + | ||
| blockedFileExtensions.compactMap { $0.utiType(mime: false) } | ||
| } | ||
|
|
||
| // MARK: - URL Validation | ||
|
|
||
| func isAllowed(localURL: URL) -> Bool { | ||
| guard !localURL.pathExtension.isEmpty else { return true } | ||
|
|
||
|
Comment on lines
39
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== target file outline =="
ast-grep outline Sources/StreamChat/Models/AppSettings+Extensions.swift --view expanded || true
echo
echo "== target file excerpt =="
nl -ba Sources/StreamChat/Models/AppSettings+Extensions.swift | sed -n '1,220p'
echo
echo "== usages of isAllowed(localURL:) =="
rg -n "isAllowed\\(localURL:" -S Sources || true
echo
echo "== references to AttachmentFileType(ext: or mimeType checks =="
rg -n "AttachmentFileType\\(ext:|mimeType|allowedFileExtensions|allowedMimeTypes|upload validation|isAllowed\\(" Sources -S || trueRepository: GetStream/stream-chat-swift Length of output: 514 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== target file excerpt =="
sed -n '1,180p' Sources/StreamChat/Models/AppSettings+Extensions.swift | cat -n
echo
echo "== usages of isAllowed(localURL:) =="
rg -n "isAllowed\\(localURL:" Sources -S || true
echo
echo "== nearby upload validation references =="
rg -n "allowedFileExtensions|allowedMimeTypes|isAllowed\\(|AttachmentFileType\\(|mimeType" Sources/StreamChat -S || trueRepository: GetStream/stream-chat-swift Length of output: 11946 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== AttachmentQueueUploader excerpt around validation =="
sed -n '150,210p' Sources/StreamChat/Workers/Background/AttachmentQueueUploader.swift | cat -n
echo
echo "== AttachmentFileType initializer and mimeType =="
sed -n '260,330p' Sources/StreamChat/Models/Attachments/AttachmentTypes.swift | cat -n
echo
echo "== AttachmentFileType ext-based usage =="
rg -n "init\\(ext:|AttachmentFileType\\(ext:" Sources/StreamChat/Models/Attachments/AttachmentTypes.swift Sources/StreamChat -S || trueRepository: GetStream/stream-chat-swift Length of output: 6781 Extensionless uploads bypass configured upload validation
🤖 Prompt for AI Agents |
||
| if !allowedFileExtensions.isEmpty || !blockedFileExtensions.isEmpty { | ||
|
Check warning on line 42 in Sources/StreamChat/Models/AppSettings+Extensions.swift
|
||
| if !isAllowed(pathExtension: localURL.pathExtension.lowercased()) { | ||
| return false | ||
| } | ||
|
|
@@ -94,7 +52,7 @@ | |
| } | ||
| return true | ||
| } | ||
|
|
||
| private func isAllowed(pathExtension: String) -> Bool { | ||
| let isBlocked = blockedFileExtensions.contains { blocked in | ||
| blocked.drop(while: { $0 == Character(".") }).caseInsensitiveCompare(pathExtension) == .orderedSame | ||
|
|
@@ -105,7 +63,7 @@ | |
| allowed.drop(while: { $0 == Character(".") }).caseInsensitiveCompare(pathExtension) == .orderedSame | ||
| } | ||
| } | ||
|
|
||
| private func isAllowed(mimeType: String) -> Bool { | ||
| let isBlocked = blockedMimeTypes.contains { blocked in | ||
| blocked.caseInsensitiveCompare(mimeType) == .orderedSame | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
sizeLimitInBytescan no longer represent "no limit configured".sizeLimit(generated) is a non-optionalInt, soInt64(sizeLimit)never returnsnil. Given the codebase's own convention elsewhere (ComposerVC.maxAttachmentSizetreatssizeLimit <= 0as "use default"), the deprecatedsizeLimitInBytespreviously likely returnednilto signal "no limit configured." Any remaining caller (internal or third-party via this public deprecated API) branching onnilvs a value will now always take the "configured" branch, silently changing behavior for the 0/unset case.🐛 Proposed fix to preserve nil semantics
📝 Committable suggestion
🤖 Prompt for AI Agents