Compare commits
2 Commits
0948fd50b4
...
5e716f2581
| Author | SHA1 | Date | |
|---|---|---|---|
| 5e716f2581 | |||
| 632f07f72a |
@ -4,6 +4,7 @@ import com.google.gson.Gson
|
||||
import jakarta.servlet.http.Cookie
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import jakarta.servlet.http.HttpServletResponse
|
||||
import kr.lunaticbum.back.lun.model.UserManager
|
||||
import kr.lunaticbum.back.lun.service.JwtService
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.lang.Nullable
|
||||
@ -19,14 +20,19 @@ class BumsInterceptor : HandlerInterceptor {
|
||||
lateinit var jwtService : JwtService
|
||||
@Autowired
|
||||
lateinit var globalEvv : GlobalEnvironment
|
||||
@Autowired
|
||||
lateinit var userManager: UserManager
|
||||
|
||||
val WRITE_PERMISSION_KEY = "PERMISSION"
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean {
|
||||
println("===============================================")
|
||||
println("==================== BEGIN ====================")
|
||||
println("Request URL ===> " + request.requestURL)
|
||||
var skippResourcesExtension = arrayListOf(".js",".css").filter { request.requestURI.contains(it) }.size > 0
|
||||
if (!skippResourcesExtension) {
|
||||
println("===============================================")
|
||||
println("==================== BEGIN ====================")
|
||||
println("Request URL ===> " + request.requestURL)
|
||||
}
|
||||
return super.preHandle(request, response, handler)
|
||||
}
|
||||
|
||||
@ -38,52 +44,75 @@ class BumsInterceptor : HandlerInterceptor {
|
||||
handler: Any,
|
||||
@Nullable modelAndView: ModelAndView?
|
||||
) {
|
||||
if (request.requestURI.contains("logout") == false && !request.cookies.isNullOrEmpty() && request.cookies.filter { it.name.equals("access") && it.value.length > 0 }.size > 0) {
|
||||
var correctUserCheck = -1;
|
||||
var access : Cookie?= null
|
||||
var refresh : Cookie?= null
|
||||
request.cookies.forEach {
|
||||
if (it.name.equals("access", true) && jwtService.validateAccessToken(it.value)){
|
||||
access = it
|
||||
correctUserCheck += 1
|
||||
println("Response access correctUserCheck ===> ${correctUserCheck}")
|
||||
var skippResourcesExtension = arrayListOf(".js",".css").filter { request.requestURI.contains(it) }.size > 0
|
||||
if (!skippResourcesExtension) {
|
||||
if (request.requestURI.contains("logout") == false && !request.cookies.isNullOrEmpty() && request.cookies.filter {
|
||||
it.name.equals(
|
||||
"access"
|
||||
) && it.value.length > 0
|
||||
}.size > 0) {
|
||||
var refreshOk = false;
|
||||
var accessOk = false;
|
||||
var access: Cookie? = null
|
||||
var refresh: Cookie? = null
|
||||
request.cookies.forEach {
|
||||
if (it.name.equals("access", true) && jwtService.validateAccessToken(it.value)) {
|
||||
access = it
|
||||
accessOk = true
|
||||
println("==================== accessOk ${accessOk} ======================")
|
||||
}
|
||||
}
|
||||
}
|
||||
request.cookies.forEach {
|
||||
if (it.name.equals("refresh", true) && jwtService.validateRefreshToken(access?.value,it.value)){
|
||||
refresh = it
|
||||
correctUserCheck += 1
|
||||
println("Response refresh correctUserCheck ===> ${correctUserCheck}")
|
||||
request.cookies.forEach {
|
||||
if (it.name.equals("refresh", true) && jwtService.validateRefreshToken(access?.value, it.value)) {
|
||||
refresh = it
|
||||
refreshOk = true
|
||||
println("==================== refreshOk ${refreshOk} ======================")
|
||||
}
|
||||
}
|
||||
}
|
||||
if (correctUserCheck > 0) {
|
||||
println("Response correctUserCheck ===> ${correctUserCheck}")
|
||||
response.addCookie(cookieUpdate(refresh))
|
||||
response.addCookie(cookieUpdate(access))
|
||||
modelAndView?.modelMap?.put(WRITE_PERMISSION_KEY,"OK")
|
||||
modelAndView?.modelMap?.put("user_id", jwtService.getUserIdFromToken(access?.value ?: ""))
|
||||
} else {
|
||||
println("Response correctUserCheck ===> ${correctUserCheck}")
|
||||
response.addCookie(Cookie("access","").apply { maxAge = -1 })
|
||||
response.addCookie(Cookie("refresh","").apply { maxAge = -1 })
|
||||
modelAndView?.modelMap?.put(WRITE_PERMISSION_KEY,"NO")
|
||||
if (refreshOk || accessOk) {
|
||||
if (refreshOk) {
|
||||
if (!accessOk) {
|
||||
refresh?.let { refresh ->
|
||||
jwtService.getUserIdFromRefresh(refresh.value)?.let { userId ->
|
||||
userManager.findById(userId)?.block()?.let { user ->
|
||||
jwtService.generate(user)?.let { token ->
|
||||
response.addCookie(cookieUpdate(Cookie("access", token.tokenKey)))
|
||||
response.addCookie(cookieUpdate(Cookie("refresh", token.refreshToken)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
response.addCookie(cookieUpdate(access))
|
||||
}
|
||||
} else if (accessOk) {
|
||||
response.addCookie(cookieUpdate(access))
|
||||
}
|
||||
modelAndView?.modelMap?.put(WRITE_PERMISSION_KEY, "OK")
|
||||
modelAndView?.modelMap?.put("user_id", jwtService.getUserIdFromToken(access?.value ?: ""))
|
||||
} else {
|
||||
println("==================== accessOk ${accessOk} && refreshOk ${refreshOk} ======================")
|
||||
response.addCookie(Cookie("access", "").apply { maxAge = -1 })
|
||||
response.addCookie(Cookie("refresh", "").apply { maxAge = -1 })
|
||||
modelAndView?.modelMap?.put(WRITE_PERMISSION_KEY, "NO")
|
||||
modelAndView?.modelMap?.put("user_id", "")
|
||||
}
|
||||
println("Response modelMap ===> ${Gson().toJson(modelAndView?.modelMap)}")
|
||||
} else if (request.requestURI.contains("logout")) {
|
||||
modelAndView?.modelMap?.put(WRITE_PERMISSION_KEY, "NO")
|
||||
modelAndView?.modelMap?.put("user_id", "")
|
||||
}
|
||||
println("Response modelMap ===> ${Gson().toJson(modelAndView?.modelMap)}")
|
||||
} else if (request.requestURI.contains("logout")) {
|
||||
modelAndView?.modelMap?.put(WRITE_PERMISSION_KEY,"NO")
|
||||
modelAndView?.modelMap?.put("user_id", "")
|
||||
|
||||
println("==================== END ======================")
|
||||
println("===============================================")
|
||||
}
|
||||
|
||||
println("==================== END ======================")
|
||||
println("===============================================")
|
||||
|
||||
super.postHandle(request, response, handler, modelAndView)
|
||||
}
|
||||
fun cookieUpdate(cookie: Cookie?) : Cookie? {
|
||||
cookie?.maxAge = (globalEvv.ACCESS_EXPIRATION / 1000).toInt()
|
||||
cookie?.domain = "lunaticbum.kr"
|
||||
cookie?.secure = true
|
||||
cookie?.path = "/"
|
||||
return cookie
|
||||
}
|
||||
}
|
||||
@ -36,7 +36,7 @@ class GlobalEnvironment : EnvironmentAware {
|
||||
// @Value("jwt.access-expiration")
|
||||
var ACCESS_EXPIRATION: Long = 60 * 5 * 1000L
|
||||
// @Value("jwt.refresh-expiration")
|
||||
var REFRESH_EXPIRATION: Long = 60 * 5 * 1000L
|
||||
var REFRESH_EXPIRATION: Long = 60 * 30 * 1000L
|
||||
|
||||
override fun setEnvironment(environment: Environment) {
|
||||
println ("telegramBotKey $telegramBotKey")
|
||||
|
||||
@ -37,6 +37,7 @@ class JwtGenerator {
|
||||
.compact()
|
||||
}
|
||||
|
||||
|
||||
private fun createHeader(): Map<String, Any> {
|
||||
val header: MutableMap<String, Any> = HashMap()
|
||||
header["typ"] = "JWT"
|
||||
|
||||
@ -10,6 +10,7 @@ import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.ApiKeyWordKey
|
||||
import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.EncType11
|
||||
import kr.lunaticbum.back.lun.configs.GlobalEnvironment.Companion.EncTypeKey
|
||||
import kr.lunaticbum.back.lun.model.*
|
||||
import kr.lunaticbum.back.lun.service.JwtService
|
||||
import kr.lunaticbum.back.lun.utils.LogService
|
||||
import kr.lunaticbum.back.lun.utils.getFileExtension
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
@ -135,22 +136,20 @@ class BlogController() {
|
||||
return vm
|
||||
}
|
||||
|
||||
@Autowired
|
||||
lateinit var jwtService : JwtService
|
||||
|
||||
@GetMapping("modify")
|
||||
fun modify(httpServletRequest: HttpServletRequest,@RequestParam("token") token : String?) : ResultMV{
|
||||
fun modify(httpServletRequest: HttpServletRequest, @RequestParam("token") token : String?) : ResultMV{
|
||||
logService.log("incoming modify")
|
||||
val vm = ResultMV("content/blog/modify")
|
||||
var s33Key : String? = null
|
||||
if (!httpServletRequest.cookies.isNullOrEmpty()) {
|
||||
httpServletRequest.cookies.forEach { if (it.name.equals("S33-DATA")){
|
||||
s33Key = it.value
|
||||
} }
|
||||
}
|
||||
if (TEMPTOKEN.equals(token)|| s33Key?.length ?: 0 > 5) {
|
||||
if(jwtService.hasPerrmission(httpServletRequest)) {
|
||||
postManageg.find20()?.apply {
|
||||
forEach {
|
||||
it.title = URLDecoder.decode(it.title)
|
||||
val content = URLDecoder.decode(it.content)
|
||||
it.content = if (content.length > 50) content.substring(0,50) else content
|
||||
it.content = if (content.length > 50) content.substring(0,150) else content
|
||||
}
|
||||
vm.modelMap.put("chunkedPosts", this.chunked(3))
|
||||
}
|
||||
|
||||
@ -27,10 +27,9 @@ class TokenData {
|
||||
var refreshToken : String? = null
|
||||
|
||||
constructor(tokenKey: String?, refreshToken: String?) {
|
||||
this.expireAt = LocalDateTime.now().plusSeconds(300)
|
||||
this.expireAt = LocalDateTime.now().plusSeconds(500)
|
||||
this.tokenKey = tokenKey
|
||||
this.refreshToken = refreshToken
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ package kr.lunaticbum.back.lun.service
|
||||
import io.jsonwebtoken.Claims
|
||||
import io.jsonwebtoken.Jws
|
||||
import io.jsonwebtoken.Jwts
|
||||
import jakarta.servlet.http.Cookie
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import jakarta.servlet.http.HttpServletResponse
|
||||
import kr.lunaticbum.back.lun.configs.GlobalEnvironment
|
||||
@ -68,7 +69,6 @@ class JwtService {
|
||||
}
|
||||
|
||||
|
||||
|
||||
private fun setTokenToCookie(tokenPrefix: String, token: String, maxAgeSeconds: Long): ResponseCookie {
|
||||
return ResponseCookie.from(tokenPrefix, token)
|
||||
.path("/")
|
||||
@ -139,4 +139,42 @@ class JwtService {
|
||||
return null
|
||||
}
|
||||
}
|
||||
fun getUserIdFromRefresh(token: String?): String? {
|
||||
try {
|
||||
return jwtUtil.extractToken(token,jwtUtil.getSigningKey(globalEvv.REFRESH_SECRET_KEY))?.body?.get("Identifier")
|
||||
.toString()
|
||||
} catch (e: Exception) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun hasPerrmission(request: HttpServletRequest): Boolean {
|
||||
var correctUserCheck = -1;
|
||||
if (request.requestURI.contains("logout") == false && !request.cookies.isNullOrEmpty() && request.cookies.filter { it.name.equals("access") && it.value.length > 0 }.size > 0) {
|
||||
var access : Cookie?= null
|
||||
var refresh : Cookie?= null
|
||||
request.cookies.forEach {
|
||||
if (it.name.equals("access", true) && validateAccessToken(it.value)){
|
||||
access = it
|
||||
correctUserCheck += 1
|
||||
}
|
||||
}
|
||||
request.cookies.forEach {
|
||||
if (it.name.equals("refresh", true) && validateRefreshToken(access?.value,it.value)){
|
||||
refresh = it
|
||||
correctUserCheck += 1
|
||||
}
|
||||
}
|
||||
if (correctUserCheck > 0) {
|
||||
println("Response correctUserCheck ===> ${correctUserCheck}")
|
||||
} else {
|
||||
println("Response correctUserCheck ===> ${correctUserCheck}")
|
||||
}
|
||||
} else if (request.requestURI.contains("logout")) {
|
||||
|
||||
}
|
||||
return correctUserCheck > 0
|
||||
}
|
||||
}
|
||||
@ -8,8 +8,9 @@
|
||||
}
|
||||
|
||||
html {
|
||||
background-image: url("data:image/svg+xml,<svg id='patternId' width='100%' height='100%' xmlns='http://www.w3.org/2000/svg'><defs><pattern id='a' patternUnits='userSpaceOnUse' width='46.5' height='46.5' patternTransform='scale(1) rotate(0)'><rect x='0' y='0' width='100%' height='100%' fill='%23000000ff'/><path d='M27.31-2.917a5 5 0 010 5.834m-8.12 0a5 5 0 010-5.834m-4.827 7.501a10 10 0 010-9.169m17.774.001a10 10 0 010 9.169M10.181 7.36a15 15 0 01-.001-14.722m26.14 0a15 15 0 010 14.724m-9.01 36.22a5 5 0 010 5.835m-8.12 0a5 5 0 010-5.834m-4.827 7.501a10 10 0 010-9.169m17.774.001a10 10 0 010 9.169M10.181 53.86a15 15 0 01-.001-14.723m26.14 0a15 15 0 010 14.724m6.12-27.693a5 5 0 010-5.834m-4.827 7.5a10 10 0 010-9.169M33.431 30.61a15 15 0 01-.001-14.722M4.06 20.332a5 5 0 010 5.835m4.827-7.501a10 10 0 010 9.169m4.183-11.947a15 15 0 010 14.724' stroke-linecap='square' stroke-width='1.5' stroke='%23c15d1ae3' fill='none'/><path d='M43.582 42.44a5 5 0 015.835 0m-7.501-4.827a10 10 0 019.169 0M39.138 33.43a15 15 0 0114.724 0m-56.781 9.01a5 5 0 015.836 0m-7.501-4.827a10 10 0 019.169 0M-7.362 33.43a15 15 0 0114.724 0M49.417 4.06a5 5 0 01-5.834 0m7.501 4.827a10 10 0 01-9.169 0m11.946 4.182a15 15 0 01-14.723.001M2.917 4.06a5 5 0 01-5.834 0m7.501 4.827a10 10 0 01-9.169 0M7.36 13.069a15 15 0 01-14.722.001m27.694 6.12a5 5 0 015.835 0m0 8.12a5 5 0 01-5.834 0m7.5 4.827a10 10 0 01-9.168 0m.001-17.774a10 10 0 019.169 0m2.776 21.956a15 15 0 01-14.723.001m0-26.14a15 15 0 0114.724 0' stroke-linecap='square' stroke-width='1.5' stroke='%23ffffff72' fill='none'/></pattern></defs><rect width='800%' height='800%' transform='translate(-93,-93)' fill='url(%23a)'/></svg>");
|
||||
margin: 1vh 1vw;
|
||||
/*background-image: url("data:image/svg+xml,<svg id='patternId' width='100%' height='100%' xmlns='http://www.w3.org/2000/svg'><defs><pattern id='a' patternUnits='userSpaceOnUse' width='46.5' height='46.5' patternTransform='scale(1) rotate(0)'><rect x='0' y='0' width='100%' height='100%' fill='%23000000ff'/><path d='M27.31-2.917a5 5 0 010 5.834m-8.12 0a5 5 0 010-5.834m-4.827 7.501a10 10 0 010-9.169m17.774.001a10 10 0 010 9.169M10.181 7.36a15 15 0 01-.001-14.722m26.14 0a15 15 0 010 14.724m-9.01 36.22a5 5 0 010 5.835m-8.12 0a5 5 0 010-5.834m-4.827 7.501a10 10 0 010-9.169m17.774.001a10 10 0 010 9.169M10.181 53.86a15 15 0 01-.001-14.723m26.14 0a15 15 0 010 14.724m6.12-27.693a5 5 0 010-5.834m-4.827 7.5a10 10 0 010-9.169M33.431 30.61a15 15 0 01-.001-14.722M4.06 20.332a5 5 0 010 5.835m4.827-7.501a10 10 0 010 9.169m4.183-11.947a15 15 0 010 14.724' stroke-linecap='square' stroke-width='1.5' stroke='%23c15d1ae3' fill='none'/><path d='M43.582 42.44a5 5 0 015.835 0m-7.501-4.827a10 10 0 019.169 0M39.138 33.43a15 15 0 0114.724 0m-56.781 9.01a5 5 0 015.836 0m-7.501-4.827a10 10 0 019.169 0M-7.362 33.43a15 15 0 0114.724 0M49.417 4.06a5 5 0 01-5.834 0m7.501 4.827a10 10 0 01-9.169 0m11.946 4.182a15 15 0 01-14.723.001M2.917 4.06a5 5 0 01-5.834 0m7.501 4.827a10 10 0 01-9.169 0M7.36 13.069a15 15 0 01-14.722.001m27.694 6.12a5 5 0 015.835 0m0 8.12a5 5 0 01-5.834 0m7.5 4.827a10 10 0 01-9.168 0m.001-17.774a10 10 0 019.169 0m2.776 21.956a15 15 0 01-14.723.001m0-26.14a15 15 0 0114.724 0' stroke-linecap='square' stroke-width='1.5' stroke='%23ffffff72' fill='none'/></pattern></defs><rect width='800%' height='800%' transform='translate(-93,-93)' fill='url(%23a)'/></svg>");*/
|
||||
/*margin: 1vh 1vw;*/
|
||||
background: black;
|
||||
}
|
||||
|
||||
#where{
|
||||
@ -23,9 +24,9 @@ body {
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
align-content: center;
|
||||
background: var(--DEFAULT_LAYER_BACK);
|
||||
padding: 1vh 1vw;
|
||||
border-radius: 10px;
|
||||
/*background: var(--DEFAULT_LAYER_BACK);*/
|
||||
/*padding: 1vh 1vw;*/
|
||||
/*border-radius: 10px;*/
|
||||
}
|
||||
|
||||
body > *{
|
||||
@ -52,8 +53,9 @@ body > *{
|
||||
header {
|
||||
top: 0;
|
||||
/*background: var(--DEFAULT_LAYER_BACK);*/
|
||||
background: var(--DEFAULT_LAYER_BACK);
|
||||
border-top: #ec914b8f;
|
||||
border-radius: 10px 30px;
|
||||
border-radius: 5px 30px;
|
||||
border-width: 1px;
|
||||
height: 5vh;
|
||||
min-height: 5vh;
|
||||
@ -159,8 +161,8 @@ footer {
|
||||
display: flex;
|
||||
bottom: 0;
|
||||
border-top: #ec914b8f;
|
||||
/*background: var(--DEFAULT_LAYER_BACK);*/
|
||||
border-radius: 30px 10px;
|
||||
background: var(--DEFAULT_LAYER_BACK);
|
||||
border-radius: 5px 30px ;
|
||||
border-width: 1px;
|
||||
height: 5vh;
|
||||
min-height: 5vh;
|
||||
|
||||
@ -1,6 +1,34 @@
|
||||
|
||||
onload = function() {
|
||||
history.replaceState({}, null, location.pathname);
|
||||
var accToken = get_cookie("access")
|
||||
var refreshToken = get_cookie("refresh")
|
||||
console.log("access === " + accToken + " || " + accToken.length);
|
||||
console.log("refresh === " + refreshToken + " || " + refreshToken.length);
|
||||
|
||||
if (accToken.length < 1) {
|
||||
document.cookie = "refresh="+ window.sessionStorage.getItem("REFRESH") + ";";
|
||||
}
|
||||
if (refreshToken.length < 1) {
|
||||
window.sessionStorage.setItem("REFRESH",get_cookie("refresh"))
|
||||
}
|
||||
}
|
||||
onbeforeunload = function () {
|
||||
var accToken = get_cookie("access")
|
||||
var refreshToken = get_cookie("refresh")
|
||||
console.log("access === " + accToken + " || " + accToken.length);
|
||||
console.log("refresh === " + refreshToken + " || " + refreshToken.length);
|
||||
|
||||
if (accToken.length < 1) {
|
||||
document.cookie = "refresh="+ window.sessionStorage.getItem("REFRESH") + ";";
|
||||
}
|
||||
if (refreshToken.length < 1) {
|
||||
window.sessionStorage.setItem("REFRESH",get_cookie("refresh"))
|
||||
}
|
||||
}
|
||||
function get_cookie(name) {
|
||||
var value = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
|
||||
return value? value[2] : null;
|
||||
}
|
||||
|
||||
function divider(key) {
|
||||
@ -92,6 +120,7 @@ function postLogin(target,type, data, key,callBackResult) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
httpRequest.open('POST', target, true);
|
||||
httpRequest.setRequestHeader("Content-Type", "text/plain");
|
||||
var odd = []
|
||||
@ -160,8 +189,11 @@ function onclickLogin(type, keyword) {
|
||||
}
|
||||
postLogin(getMainPath()+"/user/login.ajax",type,JSON.stringify(data),keyword, function (data) {
|
||||
if (data.isOk) {
|
||||
|
||||
document.cookie = "access=" + data.token.split(";")[0]+";"
|
||||
document.cookie = "refresh=" + data.refresh.split(";")[0]+";"
|
||||
// document.cookie = "refresh=" + data.refresh.split(";")[0]+";"
|
||||
// window.sessionStorage.setItem("ACCESS",data.refresh.split(";")[0])
|
||||
window.sessionStorage.setItem("REFRESH",data.refresh.split(";")[0])
|
||||
document.location.replace(document.location)
|
||||
} else {
|
||||
if (data.resultCode === 7100) {
|
||||
|
||||
39
src/main/resources/static/js/test.js
Normal file
39
src/main/resources/static/js/test.js
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
var stock = []
|
||||
function dd(... args) {
|
||||
stock.push(args)
|
||||
console.log("DD " + args)
|
||||
}
|
||||
|
||||
|
||||
function log() {
|
||||
if (stock.length > 0) {
|
||||
var fff = stock.pop()
|
||||
f(fff)
|
||||
}
|
||||
}
|
||||
|
||||
function f(a,b,c) {
|
||||
console.log("TEST" , arguments.callee.toString().split("{")[0].split(",").length)
|
||||
console.log(arguments.callee)
|
||||
if(a.length > 0) {
|
||||
console.log(a.length)
|
||||
c = a[2]
|
||||
b = a[1]
|
||||
a = a[0]
|
||||
} else {
|
||||
console.log(arguments.length)
|
||||
}
|
||||
console.log("a = " + a)
|
||||
console.log("b = " + b )
|
||||
console.log("c = " + c )
|
||||
}
|
||||
var ffff=
|
||||
|
||||
|
||||
dd("d","44","4545")
|
||||
log()
|
||||
|
||||
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
<script type="text/javascript" th:src="@{/js/blog.js}"></script>
|
||||
<link th:href="@{/css/blog.css}" rel="stylesheet" />
|
||||
<script type="text/javascript" th:src="@{/js/toast-ui-view.js}"></script>
|
||||
<script type="text/javascript" th:src="@{/js/test.js}"></script>
|
||||
<link th:href="@{/css/toast-ui-dark.css}" rel="stylesheet" />
|
||||
<script th:inline="javascript">
|
||||
let editor
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user