diff --git a/src/main/kotlin/cc/allape/caddyfile/editor/action/GenerateRandomPasswordIntentionAction.kt b/src/main/kotlin/cc/allape/caddyfile/editor/action/GenerateRandomPasswordIntentionAction.kt new file mode 100644 index 0000000..f6193e0 --- /dev/null +++ b/src/main/kotlin/cc/allape/caddyfile/editor/action/GenerateRandomPasswordIntentionAction.kt @@ -0,0 +1,47 @@ +package cc.allape.caddyfile.editor.action + +import cc.allape.caddyfile.ElementFactory +import com.intellij.codeInsight.intention.IntentionAction +import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo +import com.intellij.openapi.editor.Editor +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiFile +import kotlin.random.Random + +const val CharSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-" + +class GenerateRandomPasswordIntentionAction : IntentionAction { + override fun startInWriteAction(): Boolean { + return true + } + + override fun getFamilyName(): String { + return "Caddyfile password generation" + } + + override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean { + return getPasswordArg(editor, file) != null + } + + override fun getText(): String { + return "Create a URL-safe random password" + } + + override fun invoke(project: Project, editor: Editor?, file: PsiFile?) { + if (editor == null || file == null) { + return + } + + val ele = getPasswordArg(editor, file) ?: return + val password = ele.text.trim() + + val randomPassword = + (1..password.length).map { Random.nextInt(CharSet.length) }.map(CharSet::get).joinToString("") + + ele.replace(ElementFactory.createArg(project, randomPassword)) + } + + override fun generatePreview(project: Project, editor: Editor, file: PsiFile): IntentionPreviewInfo { + return IntentionPreviewInfo.EMPTY + } +} \ No newline at end of file diff --git a/src/main/kotlin/cc/allape/caddyfile/editor/action/GetPasswordArg.kt b/src/main/kotlin/cc/allape/caddyfile/editor/action/GetPasswordArg.kt new file mode 100644 index 0000000..a6952f3 --- /dev/null +++ b/src/main/kotlin/cc/allape/caddyfile/editor/action/GetPasswordArg.kt @@ -0,0 +1,50 @@ +package cc.allape.caddyfile.editor.action + +import cc.allape.caddyfile.language.psi.CaddyfileTypes +import com.intellij.openapi.editor.Editor +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import com.intellij.psi.TokenType +import com.intellij.psi.util.elementType + +fun getPasswordArg(editor: Editor?, file: PsiFile?): PsiElement? { + if (editor == null || file == null) { + return null + } + + var ele = file.findElementAt(editor.caretModel.offset) + + if (ele?.elementType == TokenType.WHITE_SPACE) { + val prevProperty = ele?.prevSibling + if (prevProperty?.elementType == CaddyfileTypes.PROPERTY) { + ele = prevProperty?.lastChild + } + } + + if (ele == null) { + return null + } + + // property: + // basic_auth + // matcher? + // hash_algorithm? + // block: + // property: + // username + // password + + val property = ele.parent + val block = property?.parent + val topProperty = block?.parent + + if ( + ele.elementType != CaddyfileTypes.ARG || + property?.elementType != CaddyfileTypes.PROPERTY || + topProperty?.firstChild?.text != "basic_auth" + ) { + return null + } + + return ele +} \ No newline at end of file diff --git a/src/main/kotlin/cc/allape/caddyfile/editor/action/HashPasswordIntentionAction.kt b/src/main/kotlin/cc/allape/caddyfile/editor/action/HashPasswordIntentionAction.kt index b0ba67c..7653d4f 100644 --- a/src/main/kotlin/cc/allape/caddyfile/editor/action/HashPasswordIntentionAction.kt +++ b/src/main/kotlin/cc/allape/caddyfile/editor/action/HashPasswordIntentionAction.kt @@ -9,55 +9,10 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.Editor import com.intellij.openapi.project.Project import com.intellij.openapi.ui.Messages -import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile -import com.intellij.psi.TokenType -import com.intellij.psi.util.elementType import kotlin.random.Random class HashPasswordIntentionAction : IntentionAction { - private fun getArgElementOrNull(editor: Editor?, file: PsiFile?): PsiElement? { - if (editor == null || file == null) { - return null - } - - var ele = file.findElementAt(editor.caretModel.offset) - - if (ele?.elementType == TokenType.WHITE_SPACE) { - val prevProperty = ele?.prevSibling - if (prevProperty?.elementType == CaddyfileTypes.PROPERTY) { - ele = prevProperty?.lastChild - } - } - - if (ele == null) { - return null - } - - // property: - // basic_auth - // matcher? - // hash_algorithm? - // block: - // property: - // username - // password - - val property = ele.parent - val block = property?.parent - val topProperty = block?.parent - - if ( - ele.elementType != CaddyfileTypes.ARG || - property?.elementType != CaddyfileTypes.PROPERTY || - topProperty?.firstChild?.text != "basic_auth" - ) { - return null - } - - return ele - } - override fun startInWriteAction(): Boolean { return true } @@ -67,7 +22,7 @@ class HashPasswordIntentionAction : IntentionAction { } override fun isAvailable(project: Project, editor: Editor?, file: PsiFile?): Boolean { - return getArgElementOrNull(editor, file) != null + return getPasswordArg(editor, file) != null } override fun getText(): String { @@ -79,7 +34,7 @@ class HashPasswordIntentionAction : IntentionAction { return } - val ele = getArgElementOrNull(editor, file) ?: return + val ele = getPasswordArg(editor, file) ?: return val property = ele.parent val block = property?.parent val topProperty = block?.parent diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 58ee477..e5ee1b4 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -86,8 +86,13 @@ Caddyfile - Caddyfile/password/hashing + Caddyfile/password/hash cc.allape.caddyfile.editor.action.HashPasswordIntentionAction + + Caddyfile + Caddyfile/password/generate + cc.allape.caddyfile.editor.action.GenerateRandomPasswordIntentionAction + \ No newline at end of file diff --git a/src/main/resources/intentionDescriptions/GenerateRandomPasswordIntentionAction/after.Caddyfile.template b/src/main/resources/intentionDescriptions/GenerateRandomPasswordIntentionAction/after.Caddyfile.template new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/intentionDescriptions/GenerateRandomPasswordIntentionAction/before.Caddyfile.template b/src/main/resources/intentionDescriptions/GenerateRandomPasswordIntentionAction/before.Caddyfile.template new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/intentionDescriptions/GenerateRandomPasswordIntentionAction/description.html b/src/main/resources/intentionDescriptions/GenerateRandomPasswordIntentionAction/description.html new file mode 100644 index 0000000..785e4c3 --- /dev/null +++ b/src/main/resources/intentionDescriptions/GenerateRandomPasswordIntentionAction/description.html @@ -0,0 +1,9 @@ + + +Create a URL-safe random password base on the same length of current password. +

+(1..password.length).map { Random.nextInt(CharSet.length) }.map(CharSet::get).joinToString("")
+
+ + + \ No newline at end of file diff --git a/src/main/resources/intentionDescriptions/HashPasswordIntentionAction/description.html b/src/main/resources/intentionDescriptions/HashPasswordIntentionAction/description.html index 266e2df..24efbb1 100644 --- a/src/main/resources/intentionDescriptions/HashPasswordIntentionAction/description.html +++ b/src/main/resources/intentionDescriptions/HashPasswordIntentionAction/description.html @@ -5,8 +5,7 @@ for more information.
Tools: https://github.com/patrickfav/bcrypt -

-// language=kotlin
+

 BCrypt.withDefaults().hashToString(Random.nextInt(8, 15), password.toCharArray())
 
diff --git a/src/test/testData/Caddyfile b/src/test/testData/Caddyfile index d97fbe3..f668b92 100644 --- a/src/test/testData/Caddyfile +++ b/src/test/testData/Caddyfile @@ -33,7 +33,7 @@ a { abc } basic_auth { - bob 12345678 + bob O5wTeDsRNyreumNXGEHzQ6QW } }