Home > OS >  Can't decode base64 encoded string
Can't decode base64 encoded string

Time:03-16

I found this little String extension that allows me to decode a base64-encoded string in Swift:

extension String {

    func base64Decoded() -> String? {
        guard let data = Data(base64Encoded: self) else { return nil }
        return String(data: data, encoding: .utf8)
    }

}

However, when I make this call:

let toBeDecoded = "Rj4PbzLkUlkQr0XUYLWIcgwMa GhiU1bY6BOn2A1Ea7pi1GSWzd3py73yPFe2CEr HLBYc39iSbDqxvCetBQEw=="
let decodedSecret = toBeDecoded.base64Decoded()!

...my app falls over trying to unwrap a nil optional.

I have checked with a few online decoder tools. Some manage it, some don't. What could be the problem here? This is a secret to an API I'm using (deleted now, of course).

CodePudding user response:

Your issue is two-fold.

The trivial part is that you are force-unwrapping an optional return type, which can easily be resolved by if let or nil coalescing.

The other part is that the encoded data is not actually a .utf8 string. It seems to be .ascii

If not knowing the actual string encoding is a problem you will regularly face, it might be worth extending the extension (!) to accommodate this.

extension String {
   func base64Decoded() -> (String, String.Encoding)? {
      let supportedEncoding: [String.Encoding] = [.ascii, .utf8, .utf16]  //etc.
      guard let data = Data(base64Encoded: self),
            let encoding = supportedEncoding.first(where: {String(data: data, encoding: $0) != nil})
      else {return nil}
      return (String(data: data, encoding: encoding)!, encoding)
   }
}

The method now also return the encoding type. If this isn't useful, revert to just returning the optional String.

Unfortunately String.Encoding is a struct with many static values rather than an enum, which means it's necessary to define the various encodings values. If it was an enum it would be simple to iterate over the .allcases values.

  • Related