Proguard causing error on org.jetbrains.exposed - kotlin

941 / 5.000
Resultados de tradução
I'm trying to use Proguard to obfuscate my application's code, but this is an almost impossible task. It is a desktop application developed in Kotlin language using TornadoFX (JavaFX), and org.jetbrains.exposed. After a lot of work, I managed to make the application compile. But when trying to run the system it gives an error message when trying to use the database functions using org.jetbrains.exposed. My application has a set of packages but I want to obfuscate only one package that contains 6 files, which is the important part of the software. But even using "keep", Proguard changes the classes and the application stops working.
I would like to know if there is a way to obfuscate only some files and tell ProGuard not to change the other files.
If it is not possible, does anyone know how to fix the problem when using the org.jetbrains.exposed library together with Proguard?
build.gradle task
task proguard(type: ProGuardTask) {
doFirst {
waveCounterJar
}
println("Performing obfuscation..")
configuration 'proguard.conf'
injars "$inputJar", filter: "!META-INF/NOTICE,!META-INF/NOTICE.txt,!META-INF/LICENSE,!META-INF/LICENSE.txt"
outjars "$outputJar"
libraryjars "${System.getProperty('java.home')}\\lib\\rt.jar"
libraryjars "${dependsDir}"
}
proguard.conf
-dontshrink
-dontoptimize
-keepkotlinmetadata
# Exclude all other class
-dontwarn !br.com.mawan.waveCounter.waveDetectionUtils.**
-keep class !br.com.mawan.waveCounter.waveDetectionUtils.** { *; }
-keep class * extends org.jetbrains.exposed.dao.IntIdTable { *; }
-keep class * extends org.jetbrains.exposed.dao.IntEntityClass { *; }
-keep class * extends org.jetbrains.exposed.dao.IntEntity { *; }
Pallet.class
package br.com.mawan.waveCounter.models
import org.jetbrains.exposed.dao.EntityID
import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass
import org.jetbrains.exposed.dao.IntIdTable
import org.joda.time.DateTime
object PalletsTable: IntIdTable() {
val palletNr = varchar("palletNr", 50)
val op = varchar("op", 50).nullable()
val palletOp = varchar("palletOp", 50).nullable()
val wave = varchar("wave", 5)
val stacks = integer("stacks")
val totalWaves = integer("totalWaves").default(0)
val totalBoards = integer("totalBoards").default(0)
val estimatedHeight = integer("estimatedHeight").default(0)
val quantity1 = integer("quantity1").default(0)
val quantity2 = integer("quantity2").default(0)
val message = varchar("message", 1000)
val createdDate = datetime("createdDate").default(DateTime.now())
val exported = bool("exported").default(false)
val disabled = bool("disabled").default(false)
}
class Pallet(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<Pallet>(PalletsTable)
var palletNr by PalletsTable.palletNr
var op by PalletsTable.op
var palletOp by PalletsTable.palletOp
var wave by PalletsTable.wave
var stacks by PalletsTable.stacks
var totalWaves by PalletsTable.totalWaves
var totalBoards by PalletsTable.totalBoards
var createdDate by PalletsTable.createdDate
var estimatedHeight by PalletsTable.estimatedHeight
var quantity1 by PalletsTable.quantity1
var quantity2 by PalletsTable.quantity2
var message by PalletsTable.message
var disabled by PalletsTable.disabled
var exported by PalletsTable.exported
}
Code where occurs error
transaction {
exec("SET ##global.time_zone = '+00:00'")
// The error occurs here
SchemaUtils.createMissingTablesAndColumns(PalletsTable, LogWebTable, ActionScannerTable, ConfigTable, ScannerDataTable)
exec("ALTER TABLE pallets CHANGE createddate createddate DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP")
}
Error
Caused by: kotlin.KotlinNullPointerException: null
at org.jetbrains.exposed.sql.Table.clone(Unknown Source)
at org.jetbrains.exposed.sql.Table.cloneWithAutoInc(Unknown Source)
at org.jetbrains.exposed.sql.Table.autoIncrement(Unknown Source)
at org.jetbrains.exposed.sql.Table.autoIncrement$default(Unknown Source)
at org.jetbrains.exposed.dao.IntIdTable.<init>(Unknown Source)
at org.jetbrains.exposed.dao.IntIdTable.<init>(Unknown Source)
at br.com.mawan.waveCounter.models.PalletsTable.<init>(Unknown Source)
at br.com.mawan.waveCounter.models.PalletsTable.<clinit>(Unknown Source)
... 26 common frames omitted

Related

Kotlin native. Serialization. Backend Internal error: Exception during IR lowering

I am trying to make a simple serializable class. But something goes wrong. Compilation fails for native build. But jvm target works fine.
Superclass:
import kotlinx.serialization.*
import kotlinx.serialization.json.*
import kotlin.native.concurrent.ThreadLocal
#Serializable
sealed class DefaultRequest {
private val id = Companion.id
private val name = this::class::simpleName.get()
#Transient
private val format = Json { encodeDefaults = true }
#ThreadLocal
protected companion object {
private var id = -1
get() { return ++field }
}
override fun toString() = format.encodeToString(this)
}
Subclass:
import kotlinx.serialization.Serializable
#Serializable
class PingRequest : DefaultRequest()
I had a look on this tutorial: https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/polymorphism.md#sealed-classes
It looks very easy and simple. But i don't understand where i did a mistake.
Error log from ide:
Compilation failed: Backend Internal error: Exception during IR lowering
File being compiled: /src/commonMain/kotlin/connection/serializable/requests/PingRequest.kt
The root cause org.jetbrains.kotlin.backend.common.CompilationException was thrown at: org.jetbrains.kotlin.ir.symbols.impl.IrBindableSymbolBase.getOwner(IrPrivateSymbolBase.kt:59)
* Source files:
* Compiler version info: Konan: 1.7.20-Beta / Kotlin: 1.7.20
* Output kind: PROGRAM
UPDATE:
So. After changing the code from this:
private val id = Companion.id
private val name = this::class::simpleName.get()
to this:
private val id: Int
private val name: String
init {
id = Companion.id
name = this::class::simpleName.get()!!
}
the problem has gone. But i still have a question. Why is it not working?
private val id = Companion.id
private val name = this::class::simpleName.get()

What is the reason for an UninitializedPropertyAccessException in #SpringBootTest with MockK and Kotlin?

I am trying to use MockK 1.10.2 with Kotlin 1.4.10 and #SpringBootTest (Spring Boot 2.2.2.RELEASE) and I can't get it run because of a
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
2020-11-05 15:00:37.878 WARN --- [ main] i.m.p.j.t.InliningClassTransformer : Failed to transform class java/lang/Object
java.lang.IllegalArgumentException: Unsupported class file major version 59
at net.bytebuddy.jar.asm.ClassReader.<init>(ClassReader.java:195)
at net.bytebuddy.jar.asm.ClassReader.<init>(ClassReader.java:176)
at net.bytebuddy.jar.asm.ClassReader.<init>(ClassReader.java:162)
at net.bytebuddy.utility.OpenedClassReader.of(OpenedClassReader.java:86)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForInlining.create(TypeWriter.java:3394)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1933)
at net.bytebuddy.dynamic.scaffold.inline.RedefinitionDynamicTypeBuilder.make(RedefinitionDynamicTypeBuilder.java:217)
at net.bytebuddy.dynamic.scaffold.inline.AbstractInliningDynamicTypeBuilder.make(AbstractInliningDynamicTypeBuilder.java:120)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:3404)
at io.mockk.proxy.jvm.transformation.InliningClassTransformer.transform(InliningClassTransformer.kt:77)
at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:246)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:563)
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
at java.instrument/sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:167)
at io.mockk.proxy.jvm.transformation.JvmInlineInstrumentation.retransform(JvmInlineInstrumentation.kt:28)
at io.mockk.proxy.common.transformation.RetransformInlineInstrumnetation$execute$1.invoke(RetransformInlineInstrumnetation.kt:19)
at io.mockk.proxy.common.transformation.RetransformInlineInstrumnetation$execute$1.invoke(RetransformInlineInstrumnetation.kt:6)
at io.mockk.proxy.common.transformation.ClassTransformationSpecMap.applyTransformation(ClassTransformationSpecMap.kt:41)
at io.mockk.proxy.common.transformation.RetransformInlineInstrumnetation.execute(RetransformInlineInstrumnetation.kt:16)
at io.mockk.proxy.jvm.ProxyMaker.inline(ProxyMaker.kt:88)
at io.mockk.proxy.jvm.ProxyMaker.proxy(ProxyMaker.kt:30)
kotlin.UninitializedPropertyAccessException: lateinit property taService has not been initialized
exception. (The same happens if I use tmpService. It doesn't matter if the imported service is in the same or a different package as the test class.)
As you can see from the code of my test class I already played around a lot but without any success so far.
package com.xxx.emr.tm
import com.xxx.data.emr.model.PatientAssignment
import com.xxx.data.tm.TMPService
import com.xxx.data.tm.model.MyType
import com.xxx.data.tm.model.MyTypeCode
import com.xxx.data.tm.model.UserAction
import com.xxx.emr.service.model.AuthenticatedUser
import io.mockk.every
import io.mockk.impl.annotations.InjectMockKs
import io.mockk.impl.annotations.SpyK
import io.mockk.junit5.MockKExtension
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.verify
import org.junit.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
#ExtendWith(SpringExtension::class, MockKExtension::class)
#SpringBootTest // (classes = [com.xxx.emr.service.MyServiceSpringBoot::class])
// #RunWith(SpringJUnit4ClassRunner::class)
// #ActiveProfiles("test")
// #EnableAutoConfiguration
// #AutoConfigureMockMvc
class MyTest {
// (
// val tmpService: TMPService,
// val taService: TaService
// )
// #InjectMockKs
// #Autowired
// #SpyK
#MockK
private lateinit var tmpService: TMPService
#InjectMockKs
#Autowired
private lateinit var taService: TaService
#Test
fun assignAToB() {
MockKAnnotations.init(this, relaxUnitFun = true)
val vId = "xxx"
val authUser: AuthenticatedUser = AuthenticatedUser.mockedUser()
val userAction = UserAction(
userId = "user_id",
actionCode = ActionType.GET_IT,
sessionId = "sessionId"
)
val xxx = MyType(
MyTypeCode.ABC.value,
MyTypeCode.ABC.name,
)
val actionResult = UserActionResult(hashMapOf("success" to true))
// every { tmpService.getXxx(any()) } returns xxx
verify( exactly = 1 ) {
tmpService.doSomething(any(), any(), any())
}
verify( exactly = 1 ) {
taService.dowhatYouWant(„vId", authUser, userAction)
}
}
Autowiring does not work...so what is my fault? How can I make the test run at all?
I think you should initialize your mocks first, by adding this in your test file for example:
#org.springframework.test.context.event.annotation.BeforeTestMethod
fun initMocks() {
org.mockito.MockitoAnnotations.initMocks(this)
}
I created a post on another thread about how to setup unit testing, comparable with your requirements:
https://stackoverflow.com/a/64669499/7919904

Error with Parcelable / Parceler when minifyEnabled true

I am getting the following error when I set minifyEnabled true:
Unable to find generated Parcelable class for com.codeworks.myapp.FirestoreModel, verify that your class is configured properly and that the Parcelable class com.codeworks.myapp.FirestoreModel$$Parcelable is generated by Parceler.
I placed the following code as shown in the parceler.org website in proguard-rules.pro:
# Parceler configuration
-keep interface org.parceler.Parcel
-keep #org.parceler.Parcel class * { *; }
-keep class **$$Parcelable { *; }
-keep class org.parceler.Parceler$$Parcels
... and added the #Keep annotation in the FirestoreModel and the Fragment's class:
#Parcel
#Keep
class FirestoreModel{
...
}
#Keep
class MyFragment: Fragment() {
...
}
and then added some pro-guard rules, or as I understood it from the examples from stackoverflow.com (because I can't understand the rules from official documentation):
-keepnames class com.codeworks.myapp.MyFragment { *; }
-keepnames class com.codeworks.myappFirestoreModel { *; }
I am still getting the following error:
2020-04-21 08:07:38.554 28188-28188/com.codeworks.myapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.codeworks.myapp, PID: 28188
h.a.d: Unable to find generated Parcelable class for com.codeworks.myappFirestoreModel, verify that your class is configured properly and that the Parcelable class com.codeworks.myappFirestoreModel$$Parcelable is generated by Parceler.
at h.a.e$b.a(:154)
at h.a.e.a(:73)
at h.a.e.a(:57)
at com.codeworks.myapp.MyFragment$onViewCreated$1.a(:103)
at com.codeworks.myapp.MyFragment$onViewCreated$1.a(:68)
at com.firebase.ui.firestore.FirestoreRecyclerAdapter.b(:158)
at androidx.recyclerview.widget.RecyclerView$g.a(:7065)
at androidx.recyclerview.widget.RecyclerView$g.a(:7107)
at androidx.recyclerview.widget.RecyclerView$v.a(:6012)
at androidx.recyclerview.widget.RecyclerView$v.a(:6279)
at androidx.recyclerview.widget.RecyclerView$v.b(:6118)
at androidx.recyclerview.widget.RecyclerView$v.d(:6114)
at androidx.recyclerview.widget.LinearLayoutManager$c.a(:2303)
at androidx.recyclerview.widget.LinearLayoutManager.a(:1627)
at androidx.recyclerview.widget.LinearLayoutManager.a(:1587)
at androidx.recyclerview.widget.LinearLayoutManager.e(:665)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(:4134)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(:3851)
at androidx.recyclerview.widget.RecyclerView.consumePendingUpdateOperations(:1897)
at androidx.recyclerview.widget.RecyclerView$a.run(:414)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:972)
at android.view.Choreographer.doCallbacks(Choreographer.java:796)
at android.view.Choreographer.doFrame(Choreographer.java:727)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
at android.os.Handler.handleCallback(Handler.java:907)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:216)
at android.app.ActivityThread.main(ActivityThread.java:7464)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:549)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:955)
Apparently, the variable names of the onViewCreated function on MyFragment are being renamed despite the pro-guard rules.
The error seems to point to this lines:
// Here... at com.codeworks.myapp.MyFragment$onViewCreated$1.a(:68)
adapter = object : FirestoreRecyclerAdapter<DpMemoModel, DpViewHolder>(options) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FirestoreViewHolder{
val view : View = LayoutInflater.from(parent.context).inflate(R.layout.firestore_cardview, parent, false)
return FirestoreViewHolder(view)
}
override fun onBindViewHolder(
holder: FirestoreViewHolder,
position: Int,
model: FirestoreModel
) {
...
// ...and Here: **at com.codeworks.myapp.MyFragment$onViewCreated$1.a(:103)**
val wrapped : Parcelable = Parcels.wrap(model)
holder.cardView.setOnClickListener {
val intent= Intent(activity, FirestoreInfoActivity::class.java)
intent.putExtra("parcel", wrapped)
startActivity(intent)
}
P.S.: I am using FirestoreRecyclerAdapter, I thought it was the best way since I was dealing with Cloud Firestore and Firebase Storage data.
I don't know what went wrong or what I've missed. I switched to #Parcelize for now. The code is a bit longer, but at least it works. Also, there is no need to use:
# Parceler configuration
-keep interface org.parceler.Parcel
-keep #org.parceler.Parcel class * { *; }
-keep class **$$Parcelable { *; }
-keep class org.parceler.Parceler$$Parcels
...in the proguard-rules.pro. All I need is #Keep annotation in the data class. I've spent a day and a half on research and trial and error, but, well, c'est la vie.

How to fix Proguard removes java.security code

I am using java.security.PublicKey in my project
However, when I enable proguard, I get the following error:
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.String java.security.PublicKey.getAlgorithm()' on a null object reference
After some investigation I found that it falls on
val entry = KeyStore.PrivateKeyEntry(keyPair.private, arrayOf(certificate)) <--- this line
keyStore.setEntry(alias, entry, keyProtection)
How do I make it work?
adding this to the proguard file does not work:
-keep class java.security.** { *; }
-keepclassmembers class java.security.** { *; }
-keep public interface java.security.Key {*;}
-keep public interface java.security.PublicKey {*;}
-keepclassmembers class * implements java.security.PublicKey {
public <methods>;
}
After even more investigations I found that a more specific line in the constructor of KeyStore.PrivateEntry() is causing the issue
And it is
Certificate[] clonedChain = chain.clone();
clonedChain[0].publicKey is left null
How do I make it clone the public key as well?
The issue was deprecated code.
I was using deprecated spongycastle code to generate a self signed certificate.
The public key in said certificate turned to be null, when on proguard.
I changed to the following:
api 'com.madgag.spongycastle:core:1.58.0.0'
api 'com.madgag.spongycastle:prov:1.58.0.0'
api 'com.madgag.spongycastle:bcpkix-jdk15on:1.58.0.0'
api 'com.madgag.spongycastle:bcpg-jdk15on:1.58.0.0'
And then:
fun KeyPair.toSelfSignedCertificate(principal: String, signatureAlgorithm: String, validity: Int): X509Certificate? {
val x500Name = X500Name("CN=$principal")
val today = Calendar.getInstance()
val notBefore = today.timeInMillis
today.add(Calendar.YEAR, validity)
val notAfter = today.timeInMillis
val sigGen: ContentSigner = JcaContentSignerBuilder(signatureAlgorithm).build(private)
val publicKeyInfo = SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(public.encoded))
val certGen = X509v3CertificateBuilder(x500Name,
RSAKeyGenParameterSpec.F4,
Date(notBefore),
Date(notAfter),
x500Name,
publicKeyInfo)
val certHolder: X509CertificateHolder = certGen.build(sigGen)
return JcaX509CertificateConverter().getCertificate(certHolder)
}
And it worked well.

Kotlin script eval and Java 11 with inline function in the DSL

Our project decided to make the "jump" and move to open implementations, and grabbing the opportunity to move the Kotlin Java compatibility to version 11.
It introduced several 3rd-party library compatibility challenges, but I was able to solve them all.
Now I use Kotlin 1.3.50 (with the new JSR223 engine) with Java 11 target and builds and runs correctly.
plugins {
kotlin("jvm") version "1.3.50"
}
dependencies {
compile(kotlin("stdlib"))
implementation(kotlin("scripting-jsr223-embeddable"))
}
configure<JavaPluginConvention> {
sourceCompatibility = JavaVersion.VERSION_11
}
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "11"
}
The application uses complex DSL scripts in the form of kts. They worked perfectly prior upgrading to 11, but fails to evaluate since switching to version 11.
When the code calls the eval:
val engine = ScriptEngineManager().getEngineByExtension("kts")!!
val building = engine.eval(src) as Building
it throws class version incompatibility exception:
javax.script.ScriptException: Cannot inline bytecode built
with JVM target 11 into bytecode that is being built with
JVM target 1.8. Please specify proper '-jvm-target' option
...
From this error, I can't determine whether the script engine compiles the script into Java 8 class and then tries to add the result to the core code; or the script tries to use a class which is not in Java 11 format.
How can fix this incompatibility or how could I debug all the project (including 3rd party) classes of their class file version?
Note: The DSL is too complex to give a clear and simple example, however I was able to eval the script of "2+2" without problem.
EDIT 1: A simplified example
After a long lets-comment-out session, I was able to locate the problem: it fails when I use a reified inline function in the script. This discovery made it possible to create a simple example:
package hu.app
import javax.script.ScriptEngineManager
import kotlin.reflect.KClass
/**
* A class representing a type-value pair
*/
class TypedProperty<T : Any>(val type: KClass<T>, initialValue: T? = null) {
var value: T? = initialValue
companion object {
inline fun <reified T : Any> create(initialValue: T? = null) = TypedProperty(T::class, initialValue)
}
}
/**
* The root object the DSL creates. Body omitted for simplicity.
*/
class Building {
// Class body is omitted for simplicity
}
/**
* The simple DSL
*/
#DslMarker
annotation class MyDsl
#MyDsl
class PropertyBuilder constructor() {
#MyDsl
val properties: Map<String, TypedProperty<*>> = mutableMapOf()
/**
* An extension function for String allowing the creation of a freely typed, but typed properties.
* This function causes the problem!
*/
#MyDsl
inline infix fun <reified T : Any> String.set(value: T?) {
val p = (properties as MutableMap).getOrPut(this, { TypedProperty.create(value) })
if (T::class == p.type)
(p as TypedProperty<T>).apply { this.value = value }
else
throw RuntimeException("Property '$this' is reassigned with different type. Original: ${p.type.simpleName}, new: ${T::class.simpleName}")
}
}
// Root of the DSL
#MyDsl
fun building(id: String = "Unnamed", op: BuildingBuilder.() -> Unit) = BuildingBuilder(id).apply(op).build()
// An interface for DSL classes with property support
#MyDsl
interface HasPropertiesBuilder {
#MyDsl
val properties: PropertyBuilder
#MyDsl
fun properties(op: PropertyBuilder.() -> Unit) = properties.op()
}
// The builder of the root object: it has properties
class BuildingBuilder(val id: String) : HasPropertiesBuilder {
override val properties = PropertyBuilder()
// This function body is omitted for simplification
fun build() : Building = Building()
}
fun main() {
// Initialize the engine (new 1.3.50 engine is used)
val engine = ScriptEngineManager().getEngineByExtension("kts")!!
// Evaluation
val res = engine.eval("""
import hu.pmi.autoparking.app.*
building {
properties {
"X" set 42
}
}
""".trimIndent()) as Building
}
In the above example, there is an extension function on String letting to create typed properties. It has reified type parameter, so it should be inline. This method cause the exception: if the "X" set 42 line is removed, the script compiles.
Digging deeper, now it is clear, that the script engine compiles into Java 8 and therefor, when it tries to inject the inline function which is in Java 11 class format, it fails.
So the new question: how could I tell the JSR223 kotlin engine to compile to version 11?