반응형

MongoDB 에서 보내오는 Date Format 형식은 아래와 같다.

 

yyyy-MM-dd'T'HH:mm:ss.SSS'Z'

2024-04-06T07:27:00.000Z

 

 

해당 날짜는 한국 시간과 일치하지 않아, 변환이 필요하다.

 

변환 도중 실패한 사례는 아래와 같다.

import java.text.SimpleDateFormat
import java.util.Date

var dateFormat = SimpleDateFormat("yyyy.MM.dd HH:mm", Locale.KOREAN)
val sdf = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US)
dateFormat.timeZone = TimeZone.getTimeZone("Asia/Seoul")

val date : Date? = sdf.parse("2024-04-06T07:27:00.000Z")

date?.let {
    Log.d("test_date", dateFormat.format(it))
}

 

위 코드는 에뮬레이터에서는 정상 동작하였으나, 실제 디바이스에서는 변환이 되지 않는 현상이 있었다.

 

 

그래서, 아래 코드로 적용 후에는 실제 디바이스에서도 변환이 정상적으로 가능하게 되었다.

 

import java.time.OffsetDateTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter

val zone = ZoneId.of("Asia/Seoul")
val fmt = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm", Locale.getDefault())

val dateTime = OffsetDateTime.parse("2024-04-06T07:27:00.000Z").atZoneSameInstant(zone)

dateTime?.let {
    Log.d("test_date", fmt.format(it))
}

 

반응형

[MongoDB] 랜섬웨어 (READ__ME_TO_RECOVER_YOUR_DATA)

Programming/Node.js 2024. 4. 6. 14:06 Posted by 생각하는로뎅
반응형

MongoDB 데이터 입력 후 자꾸 어느 순간 데이터가 증발하는 현상이 발생했다.

 

그리고 이상한 테이블과 글자가 아래 처럼 나타났다.

 

READ__ME_TO_RECOVER_YOUR_DATA

All your data is backed up. You must pay 0.0060 BTC to ~~~~~ In 48 hours, your data will be publicly disclosed and deleted. (more information: go to http://iplis.ru/data01)After paying send mail to us: rambler+11z39t@onionmail.org and we will provide a link for you to download your data. Your DBCODE is: 11Z39T

 

모든 데이터가 백업됩니다. ~~~~` 에 0.0060 BTC를 지불해야 합니다. 48시간 내에 귀하의 데이터가 공개되고 삭제됩니다. (자세한 정보: http://iplis.ru/data01로 이동) 비용을 지불한 후 rambler+11z39t@onionmail.org로 메일을 보내주시면 데이터를 다운로드할 수 있는 링크를 제공해드립니다. 귀하의 DBCODE는 11Z39T입니다.

 

검색해보니 랜섬웨어 란다. 

 

 

MongoDB 는 기 설치시 계정이 없이 admin 권한으로 접속이 가능하고, 또한 외부 망에서 접근이 안되게 설정 되어 있다.

 

툴킷으로 외부에서 접속해야했기에, 외부 허용으로 하는 순간..... 이렇게 랜섬웨어에 당하는 것이었다....!!

 

그래서 아래 처럼, 인증을 해야지 접속이 가능하도록 수정하였다.

 

 

1. mongod.conf 파일 위치를 찾는다.

ps -ef | grep mongo

 

 

 

2. vi 편집기로 연다.

vi /etc/mongod.conf

 

 

3. 아래 처럼 security 를 설정한다.

security:
  authorization: enabled

 

 

4. MongDB 를  재기동 한다.

sudo systemctl restart mongod.service

 

반응형

[Kotlin/Android] Ktor 를 이용한 Api 통신

Programming/Android 2024. 3. 24. 13:55 Posted by 생각하는로뎅
반응형

Ktor 은 Server 와 Client가 있고, 글쓴이는 Client 를 사용 한다.

 

사용할 Ktor 버전은 2.3.9 이고, 로그인 기능을 구현해 볼 것이다.

 

https://ktor.io/docs/getting-started-ktor-client.html

 

Creating a client application | Ktor

 

ktor.io

 

 

라이브러리를 사용하기 위해서, 아래와 같이 사전 작업이 필요하다.

 

0. AndroidManifest.xml 

  인터넷을 사용하기 위해서는 퍼미션을 꼭 설정해 준다.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        .....
    </application>

</manifest>

 

 

1. settings.gradle.kts

pluginManagement {
    repositories {
        ....
        maven {
            setUrl("https://kotlin.bintray.com/kotlinx")
        }
        resolutionStrategy {
            eachPlugin {
                if (requested.id.id == "kotlinx-serialization") {
                    useModule("org.jetbrains.kotlin:kotlin-serialization:${requested.version}")
                }
            }
        }
    }
}

 

 

2. build.gradle.kts : Project Level

plugins {
    ...
    id("org.jetbrains.kotlin.plugin.serialization") version "1.6.21" apply true
}

 

 

3. build.gradle.kts : app Level

plugins {
    .....
    id("kotlinx-serialization")
}

....

dependencies {

    val ktor_version = "2.3.9"

    implementation("io.ktor:ktor-client-core:$ktor_version")
    implementation("io.ktor:ktor-client-android:$ktor_version")
    implementation("io.ktor:ktor-client-json:$ktor_version")
    implementation("io.ktor:ktor-client-content-negotiation:$ktor_version")
    implementation("io.ktor:ktor-client-serialization:$ktor_version")
    implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")

}

 

 

Gradle Sync 후 코드로 구현한다.

 

4. LoginRequestBean.kt

    @Serializable 을 이용하여, JSON 송신(Request)할 data class 를 생성한다.

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/**
 * 로그인
 */
@Serializable
data class LoginRequestBean (
    @SerialName("email")
    val id : String,
    @SerialName("encryptedPassword")
    val pwd : String
)

 

 

5. LoginResultBean.kt

    @Serializable 을 이용하여, 서버로부터 JSON 수신(Receive) 결과를 받을 data class 를 생성한다.

package com.leestech.smarthealth.network.beans

import kotlinx.serialization.Serializable

/**
 * 결과
 */
@Serializable
data class LoginResultBean (val result : Boolean)

 

 

6. HttpRequest.kt

 

  1) _client 라는 HttpClient 를 객체를 생성하되, Json 통신을 하기 위한 각종 설정을 해주고,

        // http client
        private val _client : HttpClient = HttpClient(Android) {
            install(ContentNegotiation) {
                json(Json {
                    prettyPrint = true
                    isLenient = true
                    ignoreUnknownKeys = true
                })

                install(HttpTimeout) {
                    requestTimeoutMillis = _NETWORK_TIME_OUT
                    connectTimeoutMillis = _NETWORK_TIME_OUT
                    socketTimeoutMillis = _NETWORK_TIME_OUT
                }

                install(ResponseObserver) {
                    onResponse { response ->
                        Log.d("HTTP status:", "${response.status.value}")
                    }
                }

                install(DefaultRequest) {
                    header(HttpHeaders.ContentType, ContentType.Application.Json)
                }

                defaultRequest {
                    contentType(ContentType.Application.Json)
                    accept(ContentType.Application.Json)
                }
            }
        }

 

 

  2) loginRequstBean.kt 객체 생성 후 setBody 에 주입하면 JSON 으로 변환되어 전송되어 진다.

      결과는 body() 를 통해서 LoginResultBean에 JSON이 파싱되어 생성되어 진다.

// 결과 반환 객체
var response = LoginResultBean(false)
            
response = _client.post("$_serverUrl$_login") {
                    contentType(ContentType.Application.Json)
                    setBody(loginRequestBean)
                }.body()

 

 

Full 코드는 아래와 같다.

import android.util.Log
import com.leestech.smarthealth.network.beans.LoginRequestBean
import com.leestech.smarthealth.network.beans.LoginResultBean
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.engine.android.Android
import io.ktor.client.plugins.DefaultRequest
import io.ktor.client.plugins.HttpTimeout
import io.ktor.serialization.kotlinx.json.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.plugins.defaultRequest
import io.ktor.client.plugins.observer.ResponseObserver
import io.ktor.client.request.accept
import io.ktor.client.request.header
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.http.ContentType
import io.ktor.http.HttpHeaders
import io.ktor.http.contentType
import kotlinx.serialization.json.Json

class HttpRequest {

    companion object {

        const val _NETWORK_TIME_OUT = 6_000L

        // 서버 주소
        const val _serverUrl : String = "http://192.168.0.6/api/v2/"

        // 로그인
        const val _login : String = "login"

        // http client
        private val _client : HttpClient = HttpClient(Android) {
            install(ContentNegotiation) {
                json(Json {
                    prettyPrint = true
                    isLenient = true
                })

                install(HttpTimeout) {
                    requestTimeoutMillis = _NETWORK_TIME_OUT
                    connectTimeoutMillis = _NETWORK_TIME_OUT
                    socketTimeoutMillis = _NETWORK_TIME_OUT
                }

                install(ResponseObserver) {
                    onResponse { response ->
                        Log.d("HTTP status:", "${response.status.value}")
                    }
                }

                install(DefaultRequest) {
                    header(HttpHeaders.ContentType, ContentType.Application.Json)
                }

                defaultRequest {
                    contentType(ContentType.Application.Json)
                    accept(ContentType.Application.Json)
                }
            }
        }

        /**
         * 로그인 요청
         */
        suspend fun requstLogin(id : String, pwd : String) : LoginResultBean {

            // 결과 반환 객체
            var response = LoginResultBean(false)

            try {

                var loginRequestBean = LoginRequestBean(id, pwd)

                response = _client.post("$_serverUrl$_login") {
                    contentType(ContentType.Application.Json)
                    setBody(loginRequestBean)
                }.body()

                Log.i("Network", "ok")

            } catch (ex : Exception) {
                ex.message.let {
                    it.let {
                        Log.e("NetworkError", "$it")
                    }
                }

            } finally {

            }

            return response
        }


    }




}

 

 

7. 특정 액션에 따라서 아래와 같이 HttpRequest.requstLogin 를 호출하여 사용한다.

    /**
     * 로그인 요청
     */
    fun requestLogin() {

        // 로딩바 보이기
        this.binding.spLoading.visibility = View.VISIBLE

        CoroutineScope(Dispatchers.IO).launch {

            val response = HttpRequest.requstLogin(binding.edId.text.toString(), binding.edPwd.text.toString())

            CoroutineScope(Dispatchers.Main).launch {

                // 로딩바 숨기기
                binding.spLoading.visibility = View.GONE

                // 로그인 성공시
                if (response.result) {

                    // 화면 이동

                } else {

                    // 로그인 실패시
                    context?.let {
                        AlertDialog.Builder(it).apply {
                            setMessage(getString(R.string.msg_fail_login))
                            setPositiveButton(getString(R.string.ok), DialogInterface.OnClickListener { dialog, which ->
                            })
                            show()
                        }
                    }


                }
            }

        }

    }

 

반응형