New FMDB not encrypting using SqlCipher? - swift

I've added FMDB and FMDB/SQLCipher to my cocoa app in swift. I found some of the links which were telling how to export existing unencrypted sqlite3 database to encrypted one. But I want to create new encrypted database. So I followed the code like below, but database is not encrypting, still it can be open by 3rd party tool such as sql lite browser. Please help me.
private let key = "password"
let databaseFileName = "sample.db"
var pathToDatabase: String!
var database: FMDatabase!
let documentsDirectory = (NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true)[0] as NSString) as String
pathToDatabase = documentsDirectory.appending("/\(databaseFileName)")
if !FileManager.default.fileExists(atPath: pathToDatabase) {
database = FMDatabase(path: pathToDatabase!)
if database != nil {
// Open the database.
if database.open() {
database.setKey(key)
}
else {
print("Could not open the database.")
}
}
}
I checked database.setKey(key) returns false, what could be the problem?

Related

SQLite.Swift giving Error 14 on Connection

I have a routine, where the user chooses to pick a file location, then I try to create the file at that location.
First, I ask the user to choose a file path as follows:
func ChooseCreateDBPath() -> String
{
var path : String = ""
let savePanel = NSSavePanel()
savePanel.canCreateDirectories = true
savePanel.showsTagField = true
savePanel.nameFieldStringValue = "imported.sqlite"
if (savePanel.runModal() == NSApplication.ModalResponse.OK) {
let result = savePanel.url
if (result != nil) {
path = result!.path
}
}
return path
}
Having obtained the string to the path where the DB will be created, the next routine runs.
do {
self.dbConn = try Connection(strFilePath)
self.update_ui(message: "Created database: \(strFilePath)\n")
} catch {
self.update_ui(message: "Failed to create database : \(error)\n")
}
.... this seems to run no problem. I even see the sqlite file appear in the chosen location.
Now, I try to create the table and fields....
do {
let leads = Table("leads")
let idlead = Expression<Int64>("idlead")
let email = Expression<String>("email")
try self.dbConn!.run(leads.create { t in
t.column(idlead, primaryKey: true)
t.column(email)
}
)
try self.dbConn!.run(leads.createIndex(email))
} catch {
self.update_ui(message: "Failed to create tables and indexes : \(error)\n")
}
This then gives me:
"Failed to create tables and indexes : unable to open database file (code: 14)"
What I don't understand is how it can create the file, yet not be able to work with it? Any pointers would be much appreciated.
Cheers
Jase
I found the issue. The macOS sandboxing doesn't like it when you have files outside the sandbox. Even though the user can choose the file, that doesn't give SQLite the permission to write temp journal files there, and so everything fails. My fix was simply turn to off the Sandbox.

Swift 4 Sqlite database no such table error

I'm working at the very limit of my newbie understanding here and I'm struggling to understand what I'm doing wrong. So, I've created a database in DB Browser for SQLite, I've saved as a .db file and I've also exported to a .sql file. It is a single table with a numeric key and the name of a city. It's the basis of a bigger database I have planned. I've added all the FMDB stuff as per the GitHub page instructions. I've added the database to my project (dragged it from Finder into the left hand pane of Xcode). I've tried both individually and together the .db and .sql files and ensured they were added to target. I've then added the following code to viewDidLoad()' in theViewController` where I want to create an array from the database contents.
// test db code
let fileURL = try! FileManager.default
.url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("Wanderer.db")
let database = FMDatabase(url: fileURL)
guard database.open() else {
print("Unable to open database")
return
}
do {
let cities:FMResultSet = try database.executeQuery("SELECT City from Cities", values: nil)
while cities.next() {
if let result = cities.string(forColumn: "City") {
cityData.append(result)
}
}
} catch {
print("OOPS, some sort of failure")
}
//end test db code
When I run my app on the Simulator and the relevant page loads, I get the following error in my debug console:
2018-10-29 20:00:43.194628+0000 Wanderer[9708:849273] DB Error: 1 "no
such table: Cities"
2018-10-29 20:00:43.194808+0000 Wanderer[9708:849273] DB Query: SELECT
City from Cities
2018-10-29 20:00:43.194917+0000 Wanderer[9708:849273] DB Path:
/Users/robmunro2/Library/Developer/CoreSimulator/Devices/98971BF4-8901-4E3D-8D71-1CF3E4117885/data/Containers/Data/Application/7421C242-AA18-409E-BC61-ABB5FA5D2A98/Library/Application
Support/Wanderer.db OOPS, some sort of failure
What on earth am I doing wrong!?

Sending CSV file with SFTP in swift

I have a server hosted with webfaction that I would like to be able to send a csv file to from my app with FTP or SFTP. I have found many libraries that should help like ConnectionKit, NMSSH, DLSFPT, and LxFTPRequest. However, all of them are in objective-c and not swift which makes them hard to read, understand, and implement in Swift 4. I have tried to implement LXFTPRequest since I found a swift implementation for the upload and here is my code:
let fileName = "user-data.csv"
guard let path = FileManager.default.urls(for: .documentDirectory, in:.userDomainMask).first else {fatalError(ErrorMessageStrings.couldntAccessDocs.rawValue)}
let fileURL = path.appendingPathComponent(fileName)
let folderLocation = "/home/path/"
let uploadUrl = URL(string: "ftp://server-name.webfaction.com" + folderLocation)
let request = LxFTPRequest.upload()
request?.serverURL = uploadUrl
request?.localFileURL = fileURL
request?.username = "username"
request?.password = "password"
request?.successAction = { (resultClass, result) in
print("File uploaded")
}
request?.failAction = { (domain, error, errorMessage) in
print(error)
print(errorMessage?.description)
fatalError("Connection could not be made. Action was not completed.")
}
request?.progressAction = {(_ totalSize: Int, _ finishedSize: Int, _ finishedPercent: CGFloat) -> Void in
print(finishedPercent)
}
request?.start()`
Using this I almost get it to work but I end up with a 550 error "Requested action not taken. File unavailable (e.g., file not found, no access)." Looking through webfaction documentation I get the feeling that I can only send files through SFTP, which this framework doesnt support.
The doc says "To connect with FTP (for shell users only), substitute the connection type with FTP and the port number with 21." I am assuming since I am sending data from my app it does not count as a shell user and so FTP doesn't grant me access (I may be wrong here). If that is the case how would I go about using the other libraries to send my file over SFTP using Swift and not objective-c?
I ended up using NMSSH and using it in Swift it wasn't as complicated as I thought.
let session = NMSSHSession.init(host: serverHost, port: xx, andUsername: serverUsername)
session.connect()
if session.isConnected{
session.authenticate(byPassword: serverPasswordString)
if session.isAuthorized == true {
let sftpsession = NMSFTP(session: session)
sftpsession.connect()
if sftpsession.isConnected {
sftpsession.writeFile(atPath: csvFileURL.path, toFileAtPath: folderLocation)
}
}
}

Attempting to save username from twitter user to Firebase database iOS app

I'm attempting to save a twitter users username into the database for later reference my code below is executing but doesn't seem to be accessing the database or saving the username into the database and I'm really lost as to why. I'm attempting to have the username and userID so I can retrieve information about the user for a profile page in the app. So if I can avoid saving this data to the database all together that works too but I don't think it can be done that way.
fileprivate func setupTwitterButton() {
let twitterButton = TWTRLogInButton { (session, error) in
if let err = error {
print("Failed to login via Twitter: ", err)
return
}
// debug statement
//print("Successfully logged in using Twitter")
HUD.show(.labeledProgress(title: nil, subtitle: "Signing In"))
//we've authenticated twitter, time to log into firebase
guard let token = session?.authToken else { return }
guard let secret = session?.authTokenSecret else { return }
let creds = FIRTwitterAuthProvider.credential(withToken: token, secret: secret)
let dbref = FIRDatabase.database().reference()
let usersref = dbref.child("users")
let uid = session?.userID
//let user = FIRAuth.auth?.signIn
print("Creating user")
let newUserReference = usersref.child(uid!)
newUserReference.setValue(["username": session?.userName])
Okay so after some debugging it was pretty simple where I went wrong. I was trying to write to the database before I'd authenticated with the database. Once I had put my code for writing to the database after I'd authenticated it all worked correctly.

Uploading a video to S3 with swift The operation couldn’t be completed. (Cocoa error 260.)"

I am trying to upload a video file to Amazon S3
I constantly get an error 260:
Error in uploading the video: Error
Domain=NSCocoaErrorDomain Code=260 "The operation couldn’t be
completed. (Cocoa error 260.)
I read somewhere that amazon does not support asset library - is it true? and if so what do you suggest
Thanks Eran
func saveVideoToS3 () {
var uploadRequest: AWSS3TransferManagerUploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest.bucket = "BucketName"
uploadRequest.key = "KeyText"
//Move video file to the application folder so it can be read
var savedVideoURLToBeUsed = NSUserDefaults.standardUserDefaults().objectForKey("ThisIsTheVideoIWantToUse") as! String
println("Video saved in Store: \(savedVideoURLToBeUsed)")
var url: NSURL = NSURL(fileURLWithPath: savedVideoURLToBeUsed)!
uploadRequest.body = url
//uploadRequest.body = NSURL(fileURLWithPath: "file:///\(url)")
println("URL: \(url)")
let transferManager: AWSS3TransferManager = AWSS3TransferManager.defaultS3TransferManager()
transferManager.upload(uploadRequest).continueWithExecutor(AWSExecutor.mainThreadExecutor(), withBlock: { (AWSTask) -> AnyObject! in
//Handle errors
if AWSTask.error != nil {
println("Error in uploading the video: \(AWSTask.error)")
if AWSTask.error.code == 1001 {
self.saveVideoToS3()
}
// Retrive information important for later downloading
} else {
println("Video upload successful..")
var uploadResult: AnyObject! = AWSTask.result
println("Upload result: \(uploadResult)")
//Delete file from the application folder
}
return nil
})
}
Cocoa error 260 is a NSFileReadNoSuchFileError, meaning the path you specified is not valid (file is just not where you say it is), so it probably has nothing with S3 itself. There are three things why this is happening that come to my mind:
you did not use .synchronize() when saving the key to user settings
your file URL contains invalid characters
you did not write the file into filesystem properly
iOS8 Breaking change
Also please note that as of iOS8, due to changes how application work with their assigned sandboxes, you can't save absolute URL to file because next time you open application, it will be different.
Beginning in iOS 8, the Documents and Library directories are no
longer siblings of your application's bundle.
I am using two quick convenience functions that I wrote to get file from cache directory:
func cachePathWithFileName(fileName : String) -> String {
let cacheDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! String
return cacheDirectoryPath.stringByAppendingPathComponent(fileName)
}
and documents directory:
func documentsPathWithFileName(fileName : String) -> String {
let documentsDirectoryPath = NSSearchPathForDirectoriesInDomains(.CachesDirectory, .UserDomainMask, true)[0] as! String
return documentsDirectoryPath.stringByAppendingPathComponent(fileName)
}
Hopefully some of this tips help!