Skip to content

Commit

Permalink
feat: Prevent SQL Injection (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
EnriqueL8 authored Jun 1, 2018
1 parent b482cf2 commit 3c3f77d
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 34 deletions.
54 changes: 30 additions & 24 deletions Sources/SwiftKueryORM/Model.swift
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,11 @@ public extension Model {
return
}

let columns = table.columns.filter({$0.autoIncrement != true})
let valueTuples = columns.filter({values[$0.name] != nil}).map({($0, values[$0.name]!)})
let query = Insert(into: table, valueTuples: valueTuples)
self.executeQuery(query: query, using: db, onCompletion)
let columns = table.columns.filter({$0.autoIncrement != true && values[$0.name] != nil})
let parameters: [Any?] = columns.map({values[$0.name]!})
let parameterPlaceHolders: [Parameter] = parameters.map {_ in return Parameter()}
let query = Insert(into: table, columns: columns, values: parameterPlaceHolders)
self.executeQuery(query: query, parameters: parameters, using: db, onCompletion)
}

func save<I: Identifier>(using db: Database? = nil, _ onCompletion: @escaping (I?, Self?, RequestError?) -> Void) {
Expand All @@ -254,10 +255,11 @@ public extension Model {
return
}

let columns = table.columns.filter({$0.autoIncrement != true})
let valueTuples = columns.filter({values[$0.name] != nil}).map({($0, values[$0.name]!)})
let query = Insert(into: table, valueTuples: valueTuples, returnID: true)
self.executeQuery(query: query, using: db, onCompletion)
let columns = table.columns.filter({$0.autoIncrement != true && values[$0.name] != nil})
let parameters: [Any?] = columns.map({values[$0.name]!})
let parameterPlaceHolders: [Parameter] = parameters.map {_ in return Parameter()}
let query = Insert(into: table, columns: columns, values: parameterPlaceHolders, returnID: true)
self.executeQuery(query: query, parameters: parameters, using: db, onCompletion)
}

/// Find a model with an id
Expand All @@ -277,8 +279,9 @@ public extension Model {
return
}

let query = Select(from: table).where(idColumn == id.value)
Self.executeQuery(query: query, using: db, onCompletion)
let query = Select(from: table).where(idColumn == Parameter())
let parameters: [Any?] = [id.value]
Self.executeQuery(query: query, parameters: parameters, using: db, onCompletion)
}

///
Expand Down Expand Up @@ -439,15 +442,17 @@ public extension Model {
return
}

let columns = table.columns.filter({$0.autoIncrement != true})
let valueTuples = columns.filter({values[$0.name] != nil}).map({($0, values[$0.name]!)})
let columns = table.columns.filter({$0.autoIncrement != true && values[$0.name] != nil})
var parameters: [Any?] = columns.map({values[$0.name]!})
let parameterPlaceHolders: [(Column, Any)] = columns.map({($0, Parameter())})
guard let idColumn = table.columns.first(where: {$0.name == Self.idColumnName}) else {
onCompletion(nil, RequestError(rawValue: 708, reason: "Could not find id column"))
return
}

let query = Update(table, set: valueTuples).where(idColumn == id.value)
executeQuery(query: query, using: db, onCompletion)
let query = Update(table, set: parameterPlaceHolders).where(idColumn == Parameter())
parameters.append(id.value)
executeQuery(query: query, parameters: parameters, using: db, onCompletion)
}

static func delete(id: Identifier, using db: Database? = nil, _ onCompletion: @escaping (RequestError?) -> Void) {
Expand All @@ -464,8 +469,9 @@ public extension Model {
return
}

let query = Delete(from: table).where(idColumn == id.value)
Self.executeQuery(query: query, using: db, onCompletion)
let query = Delete(from: table).where(idColumn == Parameter())
let parameters: [Any?] = [id.value]
Self.executeQuery(query: query, parameters: parameters, using: db, onCompletion)
}

static func deleteAll(using db: Database? = nil, _ onCompletion: @escaping (RequestError?) -> Void) {
Expand Down Expand Up @@ -518,7 +524,7 @@ public extension Model {
Self.executeQuery(query: query, parameters: parameters, using: db, onCompletion)
}

internal func executeQuery(query: Query, using db: Database? = nil, _ onCompletion: @escaping (Self?, RequestError?) -> Void ) {
internal func executeQuery(query: Query, parameters: [Any?], using db: Database? = nil, _ onCompletion: @escaping (Self?, RequestError?) -> Void ) {
var connection: Connection
do {
connection = try Self.getConnection(using: db)
Expand All @@ -532,7 +538,7 @@ public extension Model {
onCompletion(nil, Self.convertError(error))
return
} else {
connection.execute(query: query) { result in
connection.execute(query: query, parameters: parameters) { result in
guard result.success else {
guard let error = result.asError else {
onCompletion(nil, Self.convertError(QueryError.databaseError("Query failed to execute but error was nil")))
Expand All @@ -548,7 +554,7 @@ public extension Model {
}
}

internal func executeQuery<I: Identifier>(query: Query, using db: Database? = nil, _ onCompletion: @escaping (I?, Self?, RequestError?) -> Void ) {
internal func executeQuery<I: Identifier>(query: Query, parameters: [Any?], using db: Database? = nil, _ onCompletion: @escaping (I?, Self?, RequestError?) -> Void ) {

var connection: Connection
do {
Expand All @@ -565,7 +571,7 @@ public extension Model {
onCompletion(nil, nil, Self.convertError(error))
return
} else {
connection.execute(query: query) { result in
connection.execute(query: query, parameters: parameters) { result in
guard result.success else {
guard let error = result.asError else {
onCompletion(nil, nil, Self.convertError(QueryError.databaseError("Query failed to execute but error was nil")))
Expand Down Expand Up @@ -606,7 +612,7 @@ public extension Model {
}
}

internal static func executeQuery(query: Query, using db: Database? = nil, _ onCompletion: @escaping (Self?, RequestError?) -> Void ) {
internal static func executeQuery(query: Query, parameters: [Any?], using db: Database? = nil, _ onCompletion: @escaping (Self?, RequestError?) -> Void ) {
var connection: Connection
do {
connection = try Self.getConnection(using: db)
Expand All @@ -622,7 +628,7 @@ public extension Model {
onCompletion(nil, Self.convertError(error))
return
} else {
connection.execute(query: query) { result in
connection.execute(query: query, parameters: parameters) { result in
guard result.success else {
guard let error = result.asError else {
onCompletion(nil, Self.convertError(QueryError.databaseError("Query failed to execute but error was nil")))
Expand Down Expand Up @@ -653,7 +659,7 @@ public extension Model {
}
}

internal static func executeQuery<I: Identifier>(query: Query, using db: Database? = nil, _ onCompletion: @escaping (I?, Self?, RequestError?) -> Void ) {
internal static func executeQuery<I: Identifier>(query: Query, parameters: [Any?], using db: Database? = nil, _ onCompletion: @escaping (I?, Self?, RequestError?) -> Void ) {
var connection: Connection
do {
connection = try Self.getConnection(using: db)
Expand All @@ -669,7 +675,7 @@ public extension Model {
onCompletion(nil, nil, Self.convertError(error))
return
} else {
connection.execute(query: query) { result in
connection.execute(query: query, parameters: parameters) { result in
guard result.success else {
guard let error = result.asError else {
onCompletion(nil, nil, Self.convertError(QueryError.databaseError("Query failed to execute but error was nil")))
Expand Down
2 changes: 1 addition & 1 deletion Tests/SwiftKueryORMTests/TestDelete.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class TestDelete: XCTestCase {
XCTAssertNil(error, "Delete Failed: \(String(describing: error))")
XCTAssertNotNil(connection.query, "Delete Failed: Query is nil")
if let query = connection.query {
let expectedQuery = "DELETE FROM People WHERE People.id = '1'"
let expectedQuery = "DELETE FROM People WHERE People.id = ?1"
let resultQuery = connection.descriptionOf(query: query)
XCTAssertEqual(resultQuery, expectedQuery, "Expected query \(String(describing: expectedQuery)) did not match result query: \(String(describing: resultQuery))")
}
Expand Down
2 changes: 1 addition & 1 deletion Tests/SwiftKueryORMTests/TestFind.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class TestFind: XCTestCase {
XCTAssertNil(error, "Find Failed: \(String(describing: error))")
XCTAssertNotNil(connection.query, "Find Failed: Query is nil")
if let query = connection.query {
let expectedQuery = "SELECT * FROM People WHERE People.id = '1'"
let expectedQuery = "SELECT * FROM People WHERE People.id = ?1"
let resultQuery = connection.descriptionOf(query: query)
XCTAssertEqual(resultQuery, expectedQuery, "Find Failed: Invalid query")
}
Expand Down
8 changes: 4 additions & 4 deletions Tests/SwiftKueryORMTests/TestId.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class TestId: XCTestCase {
XCTAssertNil(error, "Find Failed: \(String(describing: error))")
XCTAssertNotNil(connection.query, "Find Failed: Query is nil")
if let query = connection.query {
let expectedQuery = "SELECT * FROM People WHERE People.name = 'Joe'"
let expectedQuery = "SELECT * FROM People WHERE People.name = ?1"
let resultQuery = connection.descriptionOf(query: query)
XCTAssertEqual(resultQuery, expectedQuery, "Find Failed: Invalid query")
}
Expand All @@ -63,8 +63,8 @@ class TestId: XCTestCase {
XCTAssertNotNil(connection.query, "Update Failed: Query is nil")
if let query = connection.query {
let expectedPrefix = "UPDATE People SET"
let expectedSuffix = "WHERE People.name = 'Joe'"
let expectedUpdates = ["name = 'Joe'", "age = 38"]
let expectedSuffix = "WHERE People.name = ?3"
let expectedUpdates = ["name = ?1", "age = ?2"]
let resultQuery = connection.descriptionOf(query: query)
XCTAssertTrue(resultQuery.hasPrefix(expectedPrefix))
XCTAssertTrue(resultQuery.hasSuffix(expectedSuffix))
Expand Down Expand Up @@ -93,7 +93,7 @@ class TestId: XCTestCase {
XCTAssertNil(error, "Delete Failed: \(String(describing: error))")
XCTAssertNotNil(connection.query, "Delete Failed: Query is nil")
if let query = connection.query {
let expectedQuery = "DELETE FROM People WHERE People.name = 'Joe'"
let expectedQuery = "DELETE FROM People WHERE People.name = ?1"
let resultQuery = connection.descriptionOf(query: query)
XCTAssertEqual(resultQuery, expectedQuery, "Expected query \(String(describing: expectedQuery)) did not match result query: \(String(describing: resultQuery))")
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/SwiftKueryORMTests/TestSave.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class TestSave: XCTestCase {
if let query = connection.query {
let expectedPrefix = "INSERT INTO People"
let expectedSQLStatement = "VALUES"
let expectedDictionary = ["name": "Joe", "age": "38"]
let expectedDictionary = ["name": "?1", "age": "?2"]

let resultQuery = connection.descriptionOf(query: query)
XCTAssertTrue(resultQuery.hasPrefix(expectedPrefix))
Expand Down Expand Up @@ -96,7 +96,7 @@ class TestSave: XCTestCase {
if let query = connection.query {
let expectedPrefix = "INSERT INTO People"
let expectedSQLStatement = "VALUES"
let expectedDictionary = ["name": "Joe", "age": "38"]
let expectedDictionary = ["name": "?1", "age": "?2"]

let resultQuery = connection.descriptionOf(query: query)
XCTAssertTrue(resultQuery.hasPrefix(expectedPrefix))
Expand Down
4 changes: 2 additions & 2 deletions Tests/SwiftKueryORMTests/TestUpdate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ class TestUpdate: XCTestCase {
XCTAssertNotNil(connection.query, "Update Failed: Query is nil")
if let query = connection.query {
let expectedPrefix = "UPDATE People SET"
let expectedSuffix = "WHERE People.id = '1'"
let expectedUpdates = ["name = 'Joe'", "age = 38"]
let expectedSuffix = "WHERE People.id = ?3"
let expectedUpdates = ["name = ?1", "age = ?2"]
let resultQuery = connection.descriptionOf(query: query)
XCTAssertTrue(resultQuery.hasPrefix(expectedPrefix))
XCTAssertTrue(resultQuery.hasSuffix(expectedSuffix))
Expand Down

0 comments on commit 3c3f77d

Please sign in to comment.