Skip to content

Instantly share code, notes, and snippets.

@Erezbiox1
Created December 1, 2017 12:47
Show Gist options
  • Save Erezbiox1/ec835c91dfdf173572b706f4830358ab to your computer and use it in GitHub Desktop.
Save Erezbiox1/ec835c91dfdf173572b706f4830358ab to your computer and use it in GitHub Desktop.
package com.erezbiox1
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import java.sql.DriverManager
import java.sql.ResultSet
import java.util.*
import kotlin.reflect.KProperty
@Suppress("NullableBooleanElvis", "unused", "MemberVisibilityCanPrivate")
/**
* Created by Erezbiox1 on 30/11/2017.
* (C) 2017 Erez Rotem All Rights Reserved.
*/
abstract class AbstractUser(val id: Int) {
var username: String by SQL()
var email: String by SQL()
var password: String
get() = error("Cannot access hashed password")
set(pass) = sql("UPDATE users SET password = ?", hash(password))
companion object {
fun sql(query: String, vararg objects: Any, function: ((ResultSet?) -> Unit)? = null) {
Class.forName("com.mysql.jdbc.Driver")
val db = DriverManager.getConnection("jdbc:mysql://localhost:3306/main", "erez", "Pizza123")
val statement = db.prepareStatement(query)
objects.withIndex().forEach {
when(it.value){
is Int -> statement.setInt(it.index + 1, it.value as Int)
is Boolean -> statement.setBoolean(it.index + 1, it.value as Boolean)
else -> statement.setString(it.index + 1, it.value.toString())
}
}
val result =
if(statement.execute() && statement.resultSet.next())
statement.resultSet
else null
function?.invoke(result)
result?.close()
statement.close()
db.close()
}
inline fun <reified T> ResultSet?.get(column: Int = 1) : T? {
if(this == null)
return null
return when(T::class){
java.lang.Integer::class -> this.getInt(column) as T
java.lang.Integer::class.java -> this.getInt(column) as T
java.lang.Boolean::class -> this.getBoolean(column) as T
java.lang.Boolean::class.java -> this.getBoolean(column) as T
else -> this.getString(column) as T
}
}
private fun createHash(password: String) : String {
val random = UUID.randomUUID().toString()
return random + ":" + hash(random + password)
}
private fun matchHash(password: String, hash: String) : Boolean {
val split = hash.split(":")
val salt = split[0]
val hashed = split[1]
return hash(salt + password) == hashed
}
private fun hash(password: String): String {
return Base64.getEncoder().encodeToString(MessageDigest.getInstance("SHA-256").digest(password.toByteArray(StandardCharsets.UTF_8)))
}
@JvmStatic
protected fun registerUser(username: String, email: String, password: String) : Int {
var userId = -1
sql("SELECT id, password FROM users WHERE username = ?", username.toLowerCase()){
val pass = it?.get<String>(2)
if(pass != null){
userId =
if(hash(password.toLowerCase()) == pass)
it.get(1)!!
else -2
}
}
if(userId == -1){
sql("INSERT INTO users (username, email, password) VALUES (?, ?, ?)",
username.toLowerCase(),
email.toLowerCase(),
createHash(password.toLowerCase()))
sql("SELECT id FROM users WHERE username = ?", username.toLowerCase()){
userId = it?.get() ?: -1 // Cannot really be -1, but what the heck.
}
}
return userId
}
@JvmStatic
protected fun loginUser(username: String, password: String) : Int {
var userId = -1
sql("SELECT id, password FROM users WHERE username = ?", username.toLowerCase()){
val pass = it?.get<String>(2)
if(pass != null)
userId = if(matchHash(password.toLowerCase(), pass))
it.get(1) ?: -1
else -2
}
return userId
}
}
inner class SQL(val name: String? = null) {
inline operator fun <reified T> getValue(ref: Any?, property: KProperty<*>) : T {
var value: T? = null
sql("SELECT ${name ?: property.name} FROM users where id = ?", id){
value = it.get()
}
return value ?: error("Database Connection Error. value is null.")
}
operator fun <T> setValue(ref: Any?, property: KProperty<*>, value: T) {
sql("UPDATE users SET ${name ?: property.name} = ? WHERE id = ?", value!!, id)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment