main
swift 46 lines 1.79 KB
Raw
1 import Foundation
2
3 /// A tenant auth app's credentials.
4 ///
5 /// Mirrors `client_credentials::ClientCredentials`. On every `/v1/client/*`
6 /// request these are sent as the `client_id` and `client_secret` **query
7 /// parameters** (see `tenantURL(path:)`).
8 ///
9 /// The `appSecret` is confidential: hold it server-side (a Backend-for-Frontend
10 /// such as a Vapor service). Do not ship it in a distributed client binary or
11 /// browser bundle — native/public clients should use the OIDC or Apple flows,
12 /// or route through a backend.
13 public struct ClientCredentials: Sendable, Equatable {
14 public let appId: String
15 public let appSecret: String
16
17 public init(appId: String, appSecret: String) {
18 self.appId = appId
19 self.appSecret = appSecret
20 }
21 }
22
23 extension ClientCredentials {
24 /// Builds `<scheme>://<host>/<path>?client_id=…&client_secret=…`, plus any
25 /// extra query items, matching the Rust SDK's `base_url_builder`.
26 func tenantURL(
27 environment: SmbCloudEnvironment,
28 path: String,
29 extraQuery: [URLQueryItem] = []
30 ) -> URL {
31 var components = URLComponents()
32 components.scheme = environment.apiProtocol
33 // host may carry a port (e.g. "localhost:8088"); URLComponents.host
34 // can't hold the port, so set them via the full string instead.
35 let hostAndPort = environment.apiHost.split(separator: ":", maxSplits: 1)
36 components.host = String(hostAndPort[0])
37 if hostAndPort.count == 2 { components.port = Int(hostAndPort[1]) }
38 components.path = "/" + path
39 components.queryItems =
40 [
41 URLQueryItem(name: "client_id", value: appId),
42 URLQueryItem(name: "client_secret", value: appSecret),
43 ] + extraQuery
44 return components.url!
45 }
46 }