Skip to content

Commit

Permalink
Update api for UI ver 1.9.10
Browse files Browse the repository at this point in the history
  • Loading branch information
lhwdev committed May 5, 2022
1 parent ff37e40 commit 2495ef9
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 236 deletions.
229 changes: 170 additions & 59 deletions api/src/main/kotlin/com/lhwdev/selfTestMacro/api/findUser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@

package com.lhwdev.selfTestMacro.api

import com.lhwdev.fetch.get
import com.lhwdev.fetch.*
import com.lhwdev.fetch.http.HttpMethod
import com.lhwdev.fetch.http.Session
import com.lhwdev.fetch.http.fetch
import com.lhwdev.io.encodeBase64
import com.lhwdev.selfTestMacro.ContentTypes
import com.lhwdev.selfTestMacro.sDefaultFakeHeader
import com.lhwdev.selfTestMacro.toJsonLoose
import com.lhwdev.selfTestMacro.transkey.Transkey
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.KSerializer
Expand All @@ -20,80 +19,192 @@ import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import java.math.BigInteger
import java.net.URL
import java.security.KeyFactory
import java.security.spec.RSAPublicKeySpec
import javax.crypto.Cipher
import kotlin.random.Random


enum class LoginType { school, univ, office }
val transkeyUrl: URL = URL("https://hcs.eduro.go.kr/transkeyServlet")

@Serializable
data class GetUserTokenRequestBody internal constructor(
@SerialName("orgCode") val schoolCode: String,
@SerialName("name") val encryptedName: String,
@SerialName("birthday") val encryptedBirthday: String,
@SerialName("stdntPNo") val pageNumber: Int? = null,
@SerialName("loginType") val loginType: LoginType,
@SerialName("searchKey") val searchKey: InstituteSearchKey
)
enum class LoginType { school, univ, office }

@Serializable(UsersIdToken.Serializer::class)
data class UsersIdToken(val token: String) {
object Serializer : KSerializer<UsersIdToken> {
override val descriptor =
PrimitiveSerialDescriptor(UsersIdToken::class.java.name, PrimitiveKind.STRING)
sealed class FindUserResult {
abstract val isSuccess: Boolean

@Serializable
data class Success(
@Serializable(YesNoSerializer::class)
@SerialName("pInfAgrmYn") val agreement: Boolean,

override fun deserialize(decoder: Decoder) = UsersIdToken(decoder.decodeString())
override fun serialize(encoder: Encoder, value: UsersIdToken) {
encoder.encodeString(value.token)
@SerialName("hasPassword") val hasPassword: Boolean,

@SerialName("token") val token: UsersToken
) : FindUserResult() {
override val isSuccess: Boolean get() = true
}

// {isError: true, statusCode: 252, errorCode: 1001, data: {failCnt: 1, canInitPassword: false}}
/* switch(e.data.errorCode):
* case 1000:
* var t = "비밀번호를 5회 틀리셔서 5분후 재시도 하실 수 있습니다.";
* void 0 != e.data.data && void 0 != e.data.data.remainMinutes && (t += "\n약 ".concat(e.data.data.remainMinutes, "분 남았습니다")),
* 5 === e.data.data.failCnt && (t += "\n비밀번호를 잊으셨나요? 학교(기관)로 문의 바랍니다."),
* alert(t);
* break;
* case 1001:
* if (!1 === e.data.data.canInitPassword) {
* var n = "사용자 비밀번호가 맞지 않습니다. \n본인이나 가족이 이미 설정한 비밀번호를 입력하여 주시기 바랍니다.\n5회 틀리실 경우 5분후에 재시도 가능합니다 \n" + "현재 ".concat(e.data.data.failCnt, "회 틀리셨습니다");
* alert(n)
* }
* break;
* case 1003:
* alert("비밀번호가 초기화 되었습니다.\n다시 로그인하세요")
*/
@Serializable
data class Failed(
val isError: Boolean,
val statusCode: Int,
val errorCode: Int,
val data: Data
) : FindUserResult() {
override val isSuccess get() = false

val errorMessage: String? = when(statusCode) {
252 -> when(errorCode) {
1000 -> "비밀번호를 5회 틀려서 5분후 재시도 하실 수 있어요."
1001 -> """
사용자 비밀번호가 맞지 않아요.
본인이나 가족이 이미 설정한 비밀번호를 입력해 주세요.
5회 틀리실 경우 5분후에 재시도할 수 있어요.
현재 ${data.failedCount}회 틀리셨습니다.
""".trimIndent()
1003 -> "비밀번호가 초기화되었으니 다시 로그인해주세요."
else -> null
}
255 -> when(errorCode) {
1004 -> "입력시간이 초과되어 다시 비밀번호를 입력해주세요."
else -> null
}
else -> null
}

override fun toString(): String = when(errorCode) {
1000 -> "비밀본호를 5회 틀리셔서 5분 후 재시도하실 수 있습니다."
1001 -> "비밀번호가 맞지 않습니다. 현재 ${data.failedCount}회 실패하셨습니다."
1003 -> "비밀번호가 초기화되었습니다. 다시 로그인하세요."
else -> "알 수 없는 오류: 에러코드 $errorCode (틀린 횟수: ${data.failedCount})"
}

@Serializable
data class Data(
@SerialName("failCnt") val failedCount: Int
)
}

}

suspend fun GetUserTokenRequestBody(
institute: InstituteInfo,
name: String,
birthday: String,
loginType: LoginType,
searchKey: InstituteSearchKey
) =
GetUserTokenRequestBody(
institute.code,
encrypt(name),
encrypt(birthday),
loginType = loginType,
searchKey = searchKey
)

/*
* admnYn: "N"
* atptOfcdcConctUrl: "??????.eduro.go.kr"
* mngrClassYn: "N"
* mngrDeptYn: "N"
* orgName: "??????"
* pInfAgrmYn: "Y"
* stdntYn: "Y"
* token: "Bearer ??.???.??"
* userName: "???"
*/
@Serializable(UsersToken.Serializer::class)
data class UsersToken(val token: String) {
object Serializer : KSerializer<UsersToken> {
override val descriptor = PrimitiveSerialDescriptor(UsersToken::class.java.name, PrimitiveKind.STRING)
override fun deserialize(decoder: Decoder) = UsersToken(decoder.decodeString())
override fun serialize(encoder: Encoder, value: UsersToken) {
encoder.encodeString(value.token)
}
}
}

@Serializable
data class UserIdentifier(
@SerialName("userName") val mainUserName: String,
@SerialName("token") val token: UsersIdToken,
@Serializable(with = YesNoSerializer::class) @SerialName("stdntYn") val isStudent: Boolean
class InstituteResult(
val regionCode: String,
val schoolLevelCode: String?,
val loginType: LoginType,
val info: InstituteInfo
)

class UserQuery(val name: String, val birthday: String)


suspend fun Session.findUser(institute: InstituteInfo, request: GetUserTokenRequestBody): UserIdentifier = fetch(
institute.requestUrl["findUser"],
method = HttpMethod.post,
headers = sDefaultFakeHeader + mapOf("Content-Type" to ContentTypes.json),
body = JsonEncodeDefaults.encodeToString(
GetUserTokenRequestBody.serializer(),
request

suspend fun Session.findUser(
institute: InstituteResult,
searchKey: InstituteSearchKey,

userQuery: UserQuery,

password: String,

makeSession: Boolean = true,
deviceUuid: String = "",
pageNumber: Int? = null
): FindUserResult {
val transkey = Transkey(this, transkeyUrl, Random)

val keyPad = transkey.newKeypad(
keyType = "number",
name = "password",
inputName = "password",
fieldType = "password"
)
).toJsonLoose(UserIdentifier.serializer())

val encrypted = keyPad.encryptPassword(password)

val hm = transkey.hmacDigest(encrypted.toByteArray())

val raonPassword = jsonString {
"raon" jsonArray {
addJsonObject {
"id" set "password"
"enc" set encrypted
"hmac" set hm
"keyboardType" set "number"
"keyIndex" set keyPad.keyIndex
"fieldType" set "password"
"seedKey" set transkey.crypto.encryptedKey
"initTime" set transkey.initTime
"ExE2E" set "false"
}
}
}

val encryptedName = encrypt(userQuery.name)
val encryptedBirthday = encrypt(userQuery.birthday)

val result = fetch(
institute.info.requestUrl["/v3/findUser"],
method = HttpMethod.post,
headers = sDefaultFakeHeader + mapOf(
"Accept" to "application/json, text/plain, */*"
),
body = Bodies.jsonObject {
"birthday" set encryptedBirthday
"deviceUuid" set ""
if(institute.schoolLevelCode != null) {
"lctnScCode" set institute.schoolLevelCode
}
"loginType" set institute.loginType.name
"makeSession" set makeSession
"name" set encryptedName
"orgCode" set institute.info.code
"orgName" set institute.info.name
"password" set raonPassword
"searchKey" set searchKey.key
if(pageNumber == null) {
"stdntPNo" set null
} else {
"stdntPNo" set pageNumber
}
}
).getText()

return try {
JsonLoose.decodeFromString(FindUserResult.Success.serializer(), result)
} catch(e: Throwable) {
JsonLoose.decodeFromString(FindUserResult.Failed.serializer(), result)
}
}


suspend fun encrypt(string: String): String = withContext(Dispatchers.IO) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,17 @@ import java.net.URL


@Serializable
data class InstituteInfoResponse(
class InstituteInfoResponse(
@SerialName("key") val searchKey: InstituteSearchKey,
@SerialName("schulList") val instituteList: List<InstituteInfo>
)

@Serializable
class InstituteInfosResult(
val searchKey: InstituteSearchKey,
val list: List<InstituteResult>
)

@Serializable(with = InstituteSearchKey.Serializer::class)
data class InstituteSearchKey(val key: String) {
object Serializer : KSerializer<InstituteSearchKey> {
Expand All @@ -44,8 +50,7 @@ data class InstituteInfo(
@SerialName("addres") val address: String,
@SerialName("atptOfcdcConctUrl") val requestUrlBody: String
) {
val requestUrl get() = URL("https://$requestUrlBody/v2")
val requestUrlBase get() = URL("https://$requestUrlBody")
val requestUrl get() = URL("https://$requestUrlBody")
}


Expand All @@ -54,7 +59,7 @@ suspend fun Session.getSchoolData(
regionCode: String,
schoolLevelCode: String,
name: String
): InstituteInfoResponse {
): InstituteInfosResult {
val params = queryUrlParamsToString(
mapOf(
"lctnScCode" to regionCode,
Expand All @@ -64,8 +69,14 @@ suspend fun Session.getSchoolData(
)
)

return fetch(url = sCommonUrl["searchSchool?$params"], method = HttpMethod.get, headers = sDefaultFakeHeader)
val result = fetch(url = sCommonUrl["searchSchool?$params"], method = HttpMethod.get, headers = sDefaultFakeHeader)
.toJsonLoose(InstituteInfoResponse.serializer())
return InstituteInfosResult(
searchKey = result.searchKey,
list = result.instituteList.map {
InstituteResult(regionCode, schoolLevelCode, LoginType.school, it)
}
)
}

// 대학: orgName=...&loginType=univ
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class UserGroup(val users: List<User>, val clientVersion: String) : List<User> b


suspend fun Session.getUserGroup(institute: InstituteInfo, token: UsersToken): UserGroup = fetch(
institute.requestUrl["selectUserGroup"],
institute.requestUrl["/v2/selectUserGroup"],
method = HttpMethod.post,
headers = sDefaultFakeHeader + mapOf("Content-Type" to ContentTypes.json, "Authorization" to token.token),
body = "{}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ data class UserInfo(
* wrongPassCnt: 0
*/
suspend fun Session.getUserInfo(institute: InstituteInfo, user: User): UserInfo = fetch(
institute.requestUrl["getUserInfo"],
institute.requestUrl["/v2/getUserInfo"],
method = HttpMethod.post,
headers = sDefaultFakeHeader + mapOf(
"Content-Type" to ContentTypes.json,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ suspend fun Session.registerSurvey(
user: User,
surveyData: SurveyData
): SurveyResult = fetch(
institute.requestUrlBase["registerServey"],
institute.requestUrl["registerServey"],
method = HttpMethod.post,
headers = sDefaultFakeHeader + mapOf(
"Content-Type" to ContentTypes.json,
Expand Down
Loading

0 comments on commit 2495ef9

Please sign in to comment.