-2

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 ?

Zohar81
  • 4,554
  • 5
  • 29
  • 82
  • 1
    "base64 symbols" are not "formatted with '%' followed by hex value." You mean percent encoding. The only base64 in this query is `eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=`, which is base64-encoded JSON (`{"bbb":"Asda", "dscvg":"asascd"}`). Which specific parameters do you want? As written, this is a scheme plus path. There is no query. I believe what you're probably looking for is www-form-urlencoded decoding. – Rob Napier Oct 17 '21 at 19:45
  • @RobNapier, You are right, I fixed my question. thanks ! basically what i want it to be able to extract the values from the url according to params (i.e. if I call extractValue(string: "token") than i'd expect to get eyJiYmIiOiJBc2RhIiwgImRzY3ZnIjoiYXNhc2NkIn0=. Ideally, I wish to take the path(out of the scheme+path) and use it to extract the values with builtin method/framwork) – Zohar81 Oct 17 '21 at 19:57
  • What do you mean by "ASCII representation"? ASCII is a character set that is used very rarely nowadays. – Sulthan Oct 17 '21 at 20:24

1 Answers1

1

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)
}
Rob Napier
  • 286,113
  • 34
  • 456
  • 610