swifturlbase64nsurlcomponents

Swift. Convert percent encoding symbols in string, to their ascii representation


I'm using the Swift framework ASWebAuthenticationSession in order to add authentication via browser for my application. After processing the credentials, the authentication provider send URL with special prefix which gets intercepted by my app. The URL has the following format :

mycallback:un%3Dtest%26as%3D1%26token%3DeyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=

Now I wish to create a method that extract param's value. So I use URLComponents. I need to replace the ':' with '?', but although it convert the percent encoding chars back into ascii, it seems like the url cannot be parsed properly

(lldb) po URLComponents(string: "mycallback%3Fun%3Dtest%26as%3D1%26token%3DeyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=")

▿ Optional<URLComponents>
  ▿ some : mycallback%3Fun%3Dtest%26as%3D1%26token%3DeyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=
    - path : "mycallback?un=test&as=1&token=eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0="


(lldb) po URLComponents(string: "mycallback%3Fun%3Dtest%26as%3D1%26token%3DeyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=")?.queryItems
nil

Another approach is use the intercepted URL as-is and get scheme+path but how can i query params out of this structure ?

(lldb) po URLComponents(string: "mycallback:un%3Dtest%26as%3D1%26token%3DeyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=")
▿ Optional<URLComponents>
  ▿ some : mycallback:un%3Dtest%26as%3D1%26token%3DeyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=
    - scheme : "mycallback"
    - path : "un=test&as=1&token=eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0="

only if I manually convert the percent encodingp symbols to their ascii representation in advance, than the query seems fine :

(lldb) po URLComponents(string: "mycallback?un=test&as=1&token=eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=")
▿ Optional<URLComponents>
  ▿ some : mycallback?un=test&as=1&token=eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=
    - path : "mycallback"
    ▿ queryItems : 3 elements
      ▿ 0 : un=test
        - name : "un"
        ▿ value : Optional<String>
          - some : "test"
      ▿ 1 : as=1
        - name : "as"
        ▿ value : Optional<String>
          - some : "1"
      ▿ 2 : token=eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=
        - name : "token"
        ▿ value : Optional<String>
          - some : "eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0="

So my question is how to convert all percent encoding symbols (formatted with '%' followed by hex value) to their ascii representation ?


Solution

  • You have an URL where the scheme is mycallback and the path is actually a query. You just need to parse and adjust it.

    func decodedParameters(string: String) -> [URLQueryItem]? {
        var c = URLComponents()
        c.query = URLComponents(string: data)?.path
        return c.queryItems
    }
    
    
    if let parameters = decodedParameters(string: data),
       let token = parameters.first(where: { $0.name == "token"})?.value {
        print(token)
    }
    
    // eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=
    

    If you're doing this a lot, you may prefer to create an extension to make it a little easier:

    extension Array where Element == URLQueryItem {
        subscript(_ key: String) -> String? {
            first(where: { $0.name == key})?.value
        }
    }
    
    let parameters = decodedParameters(string: data) ?? []
    
    if let token = parameters["token"] {
        print(token)
    }