Decoding Dreamweaver STE files with Swift

Decoding Dreamweaver STE files with Swift

We have a few clients that use Dreamweaver as their editor/FTP client of choice. This unfortunately doesn't fit in with our toolchain and as we often receive STE files it's a manual process to extract the data from the file.

Since we use the amazing Transmit from Panic I wondered if there was a way we could parse the file from Dreamweaver and open a new connection in Transmit.

Decoding The Password

First of all I wanted to see if it was actually possible to decode the password before I bothered building anything. Thankfully, the heavy lifting of figuring out how Dreamweaver stores passwords had been figured out by Bart Grantham.

Essentially, Dreamweaver converts a password string into its hexadecimal characters and then adds the index of the character to encode it. So busters would become 62767577697779.

To decode the password stored in the STE file given to us we need to do the following things in Swift:

  1. Chunk the string into an array of character pairs
  2. Convert the characters back into a string
  3. Convert the character string into its hex integer equivalent
  4. Subtract the index of the pair from the hex
  5. Convert the hex back into a character

I've created a little extension in Swift to achieve this and am also using this chunk extension as it's not a native feature of Swift currently.

Demo

Here's a quick demo of that in action. This is using that very same Swift extension on an Ubuntu server running Swift 2.2.

Result:

Parsing The STE

Once I'd figured out how to decode the password, parsing the rest of the file was pretty easy. Thankfully Adobe opted for an XML-based file so I used lovely AEXML to parse it and fetch the info for the site: username, password, host, protocol etc.

TransmitWeaver Screenshot

Opening In Transmit

Pulling all the info out was great and would probably have done the job but I wanted to see if we could get it to automatically open a new window in Transmit. If this was at all possible it seemed like AppleScript would be the best solution.

Initially I tried using a Script Bridge.

sdef /Applications/Transmit.app | sdp -fh --basename Transmit

Running the above command got the AppleScript definitions out but getting the bloody thing to work with Swift was ridiculously overcomplicated. Instead, I checked out the definitions in Script Editor.app and ran an AppleScript directly instead of via a script bridge.

AppleScript Editor

@IBAction func openInTransmit(sender: AnyObject) {
    
    let baseURL = NSBundle.mainBundle().URLForResource("baseScript", withExtension: "txt")
    if let path = baseURL?.path {
        do {
            let baseScript = try String(contentsOfFile: path)
            let replaced = baseScript
                .stringByReplacingOccurrencesOfString("{{HOST}}", withString: hostTextField.stringValue)
                .stringByReplacingOccurrencesOfString("{{USERNAME}}", withString: usernameField.stringValue)
                .stringByReplacingOccurrencesOfString("{{PASSWORD}}", withString: passwordField.stringValue)
                .stringByReplacingOccurrencesOfString("{{PATH}}", withString: pathField.stringValue)
                .stringByReplacingOccurrencesOfString("{{PROTOCOL}}", withString: protocolField.stringValue)
            
            let script = NSAppleScript(source: replaced)
            var errorPointer: NSDictionary?
            script?.executeAndReturnError(&errorPointer)
            
        } catch {
            Swift.print("Could not open base script")
        }
    }
    
}

func checkForTransmit() -> Bool {
    if NSWorkspace.sharedWorkspace().absolutePathForAppBundleWithIdentifier("com.panic.Transmit") != nil {
        return true
    }
    return false
}

GitHub

I'm aware this helps very little people. It was more a quick thing for me to try implementing drag and drop in Cocoa and to solve this minor irk.

If you'd like to check out the project it's available on GitHub.