added dedicated cli module
This commit is contained in:
@@ -3,6 +3,7 @@ module net.woggioni.gbcs.base {
|
||||
requires java.logging;
|
||||
requires org.slf4j;
|
||||
requires kotlin.stdlib;
|
||||
requires net.woggioni.jwo;
|
||||
|
||||
exports net.woggioni.gbcs.base;
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
package net.woggioni.gbcs.base
|
||||
|
||||
import java.io.InputStream
|
||||
import java.net.URL
|
||||
import java.net.URLConnection
|
||||
import java.net.URLStreamHandler
|
||||
import java.net.URLStreamHandlerFactory
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.stream.Collectors
|
||||
|
||||
|
||||
class ClasspathUrlStreamHandlerFactoryProvider : URLStreamHandlerFactory {
|
||||
private class Handler(private val classLoader: ClassLoader = ClasspathUrlStreamHandlerFactoryProvider::class.java.classLoader) : URLStreamHandler() {
|
||||
|
||||
override fun openConnection(u: URL): URLConnection? {
|
||||
return javaClass.module
|
||||
?.takeIf { m: Module -> m.layer != null }
|
||||
?.let {
|
||||
val path = u.path
|
||||
val i = path.lastIndexOf('/')
|
||||
val packageName = path.substring(0, i).replace('/', '.')
|
||||
val modules = packageMap[packageName]!!
|
||||
ModuleResourceURLConnection(
|
||||
u,
|
||||
modules
|
||||
)
|
||||
}
|
||||
?: classLoader.getResource(u.path)?.let(URL::openConnection)
|
||||
}
|
||||
}
|
||||
|
||||
override fun createURLStreamHandler(protocol: String): URLStreamHandler? {
|
||||
return when (protocol) {
|
||||
"classpath" -> Handler()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private class ModuleResourceURLConnection(url: URL?, private val modules: List<Module>) :
|
||||
URLConnection(url) {
|
||||
override fun connect() {}
|
||||
|
||||
override fun getInputStream(): InputStream? {
|
||||
for (module in modules) {
|
||||
val result = module.getResourceAsStream(getURL().path)
|
||||
if (result != null) return result
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val installed = AtomicBoolean(false)
|
||||
fun install() {
|
||||
if (!installed.getAndSet(true)) {
|
||||
URL.setURLStreamHandlerFactory(ClasspathUrlStreamHandlerFactoryProvider())
|
||||
}
|
||||
}
|
||||
|
||||
private val packageMap: Map<String, List<Module>> by lazy {
|
||||
ClasspathUrlStreamHandlerFactoryProvider::class.java.module.layer
|
||||
.modules()
|
||||
.stream()
|
||||
.flatMap { m: Module ->
|
||||
m.packages.stream()
|
||||
.map { p: String -> p to m }
|
||||
}
|
||||
.collect(
|
||||
Collectors.groupingBy(
|
||||
Pair<String, Module>::first,
|
||||
Collectors.mapping(
|
||||
Pair<String, Module>::second,
|
||||
Collectors.toUnmodifiableList<Module>()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
package net.woggioni.gbcs.base
|
||||
|
||||
import java.security.SecureRandom
|
||||
import java.security.spec.KeySpec
|
||||
import java.util.Base64
|
||||
import javax.crypto.SecretKeyFactory
|
||||
import javax.crypto.spec.PBEKeySpec
|
||||
|
||||
object PasswordSecurity {
|
||||
private const val KEY_LENGTH = 256
|
||||
|
||||
private fun concat(arr1: ByteArray, arr2: ByteArray): ByteArray {
|
||||
val result = ByteArray(arr1.size + arr2.size)
|
||||
var j = 0
|
||||
for(element in arr1) {
|
||||
result[j] = element
|
||||
j += 1
|
||||
}
|
||||
for(element in arr2) {
|
||||
result[j] = element
|
||||
j += 1
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun hashPassword(password : String, salt : String? = null) : String {
|
||||
val actualSalt = salt?.let(Base64.getDecoder()::decode) ?: SecureRandom().run {
|
||||
val result = ByteArray(16)
|
||||
nextBytes(result)
|
||||
result
|
||||
}
|
||||
val spec: KeySpec = PBEKeySpec(password.toCharArray(), actualSalt, 10, KEY_LENGTH)
|
||||
val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")
|
||||
val hash = factory.generateSecret(spec).encoded
|
||||
return String(Base64.getEncoder().encode(concat(hash, actualSalt)))
|
||||
}
|
||||
|
||||
fun decodePasswordHash(passwordHash : String) : Pair<ByteArray, ByteArray> {
|
||||
val decoded = Base64.getDecoder().decode(passwordHash)
|
||||
val hash = ByteArray(KEY_LENGTH / 8)
|
||||
val salt = ByteArray(decoded.size - KEY_LENGTH / 8)
|
||||
System.arraycopy(decoded, 0, hash, 0, hash.size)
|
||||
System.arraycopy(decoded, hash.size, salt, 0, salt.size)
|
||||
return hash to salt
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user