mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
ICS — require token for GitHub, user/pass is not allowed anymore
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
package com.intellij.credentialStore
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.util.nullize
|
||||
import java.security.MessageDigest
|
||||
import java.util.*
|
||||
|
||||
@@ -32,4 +34,60 @@ internal fun getRawKey(key: String, requestor: Class<*>?) = if (requestor == nul
|
||||
|
||||
internal fun toOldKey(hash: ByteArray) = "old-hashed-key|" + Base64.getEncoder().encodeToString(hash)
|
||||
|
||||
internal fun toOldKey(newKey: String) = toOldKey(MessageDigest.getInstance("SHA-256").digest(newKey.toByteArray()))
|
||||
internal fun toOldKey(newKey: String) = toOldKey(MessageDigest.getInstance("SHA-256").digest(newKey.toByteArray()))
|
||||
|
||||
fun joinData(user: String?, password: String?) = "${StringUtil.escapeChars(user.orEmpty(), '\\', '@')}@$password"
|
||||
|
||||
fun splitData(data: String): Credentials? {
|
||||
if (data.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
|
||||
val list = parseString(data, '@')
|
||||
val result = Credentials(list.getOrNull(0), list.getOrNull(1))
|
||||
return if (result.isFulfilled()) result else null
|
||||
}
|
||||
|
||||
private const val ESCAPING_CHAR = '\\'
|
||||
|
||||
private fun parseString(data: String, delimiter: Char): List<String> {
|
||||
val part = StringBuilder()
|
||||
val result = ArrayList<String>(2)
|
||||
var i = 0
|
||||
var c: Char?
|
||||
do {
|
||||
c = data.getOrNull(i++)
|
||||
if (c != null && c != delimiter) {
|
||||
if (c == ESCAPING_CHAR) {
|
||||
c = data.getOrNull(i++)
|
||||
}
|
||||
|
||||
if (c != null) {
|
||||
part.append(c)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
result.add(part.toString())
|
||||
part.setLength(0)
|
||||
}
|
||||
while (c != null)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
class Credentials(user: String?, password: String?) {
|
||||
val user = user.nullize()
|
||||
val password = password.nullize()
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is Credentials) return false
|
||||
return user == other.user && password == other.password
|
||||
}
|
||||
|
||||
override fun hashCode() = (user?.hashCode() ?: 0) * 37 + (password?.hashCode() ?: 0)
|
||||
|
||||
override fun toString() = joinData(user, password)
|
||||
}
|
||||
|
||||
fun Credentials?.isFulfilled() = this != null && user != null && password != null
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.intellij.credentialStore
|
||||
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.Test
|
||||
class CredentialTest {
|
||||
@Test
|
||||
fun join() {
|
||||
test("foo", "pass", "foo@pass")
|
||||
test("foo@", "pass", "foo\\@@pass")
|
||||
test("\\foo@", "pass", "\\\\foo\\@@pass")
|
||||
test("\\foo\\", "pass", "\\\\foo\\\\@pass")
|
||||
test("", "pass", "@pass")
|
||||
test("foo", "", "foo@")
|
||||
}
|
||||
|
||||
private fun test(u: String, p: String, joined: String) {
|
||||
assertThat(joinData(u, p)).isEqualTo(joined)
|
||||
assertThat(splitData(joined)).isEqualTo(Credentials(u, p))
|
||||
}
|
||||
}
|
||||
@@ -17,13 +17,17 @@ package com.intellij.openapi.ui
|
||||
|
||||
import javax.swing.JComponent
|
||||
|
||||
fun dialog(title: String, centerPanel: JComponent, resizable: Boolean = true): DialogBuilder {
|
||||
fun dialog(title: String, centerPanel: JComponent, resizable: Boolean = true, preferedFocusComponent: JComponent? = null, okActionEnabled: Boolean = true): DialogBuilder {
|
||||
val builder = DialogBuilder()
|
||||
builder
|
||||
.title(title)
|
||||
.centerPanel(centerPanel)
|
||||
.setPreferredFocusComponent(preferedFocusComponent)
|
||||
if (!resizable) {
|
||||
builder.resizable(false)
|
||||
}
|
||||
if (!okActionEnabled) {
|
||||
builder.okActionEnabled(false)
|
||||
}
|
||||
return builder
|
||||
}
|
||||
@@ -63,7 +63,7 @@ enum class CCFlags {
|
||||
*/
|
||||
span,
|
||||
|
||||
grow, push, pushY, pushX, right
|
||||
grow, push, pushY, pushX, right, skip
|
||||
}
|
||||
|
||||
inline fun panel(vararg layoutConstraints: LCFlags, init: Panel.() -> Unit): JPanel {
|
||||
@@ -209,6 +209,7 @@ fun CC.apply(flags: Array<out CCFlags>): CC {
|
||||
CCFlags.pushY -> pushY()
|
||||
|
||||
CCFlags.span -> span()
|
||||
CCFlags.skip -> skip()
|
||||
}
|
||||
}
|
||||
return this
|
||||
|
||||
@@ -17,6 +17,6 @@ package com.intellij.util
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
|
||||
fun String?.nullize(): String? = StringUtil.nullize(this)
|
||||
fun String?.nullize(nullizeSpaces: Boolean = false): String? = StringUtil.nullize(this, nullizeSpaces)
|
||||
|
||||
fun String.trimMiddle(maxLength: Int): String? = StringUtil.trimMiddle(this, maxLength)
|
||||
@@ -32,7 +32,7 @@ settings.update.on.start=Update repository from upstream on start
|
||||
|
||||
sync.repositories.panel.title=Sync Repositories
|
||||
|
||||
login.github.note=Strongly recommended to use an <a href="https://help.github.com/articles/creating-an-access-token-for-command-line-use">access token</a>.
|
||||
login.github.note=<a href="https://help.github.com/articles/creating-an-access-token-for-command-line-use">How to create an access token</a>.
|
||||
login.other.git.provider.note=Consider to configure <a href="https://help.github.com/articles/caching-your-github-password-in-git">git credentials helper</a>.
|
||||
settings.upstream.url=Upstream URL\:
|
||||
|
||||
|
||||
@@ -24,5 +24,6 @@
|
||||
<orderEntry type="module" module-name="settings-repository" />
|
||||
<orderEntry type="library" scope="TEST" name="assertJ" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="memoryfilesystem" level="project" />
|
||||
<orderEntry type="module" module-name="credential-store" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -15,39 +15,110 @@
|
||||
*/
|
||||
package org.jetbrains.settingsRepository
|
||||
|
||||
import com.intellij.credentialStore.Credentials
|
||||
import com.intellij.layout.*
|
||||
import com.intellij.layout.CCFlags.*
|
||||
import com.intellij.layout.LCFlags.*
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.ui.dialog
|
||||
import com.intellij.openapi.util.Computable
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vcs.changes.issueLinks.LinkMouseListenerBase
|
||||
import com.intellij.ui.DocumentAdapter
|
||||
import com.intellij.ui.JBColor
|
||||
import com.intellij.ui.SimpleColoredComponent
|
||||
import com.intellij.ui.SimpleTextAttributes
|
||||
import com.intellij.util.PathUtilRt
|
||||
import com.intellij.util.nullize
|
||||
import com.intellij.util.trimMiddle
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import org.jetbrains.keychain.Credentials
|
||||
import java.util.regex.Pattern
|
||||
import javax.swing.JPasswordField
|
||||
import javax.swing.JTextField
|
||||
import javax.swing.event.DocumentEvent
|
||||
|
||||
private val HREF_PATTERN = Pattern.compile("<a(?:\\s+href\\s*=\\s*[\"']([^\"']*)[\"'])?\\s*>([^<]*)</a>")
|
||||
private val LINK_TEXT_ATTRIBUTES = SimpleTextAttributes(SimpleTextAttributes.STYLE_SMALLER, JBColor.blue)
|
||||
private val SMALL_TEXT_ATTRIBUTES = SimpleTextAttributes(SimpleTextAttributes.STYLE_SMALLER, null)
|
||||
|
||||
fun showAuthenticationForm(credentials: Credentials?, uri: String, host: String?, path: String?, sshKeyFile: String?): Credentials? {
|
||||
if (ApplicationManager.getApplication()?.isUnitTestMode === true) {
|
||||
throw AssertionError("showAuthenticationForm called from tests")
|
||||
}
|
||||
|
||||
return UIUtil.invokeAndWaitIfNeeded(Computable {
|
||||
val note = if (sshKeyFile == null) icsMessage(if (host == "github.com") "login.github.note" else "login.other.git.provider.note") else null
|
||||
var username = credentials?.id
|
||||
if (username == null && host == "github.com" && path != null && sshKeyFile == null) {
|
||||
val isGitHub = host == "github.com"
|
||||
val note = if (sshKeyFile == null) icsMessage(if (isGitHub) "login.github.note" else "login.other.git.provider.note") else null
|
||||
var username = credentials?.user
|
||||
if (username == null && isGitHub && path != null && sshKeyFile == null) {
|
||||
val firstSlashIndex = path.indexOf('/', 1)
|
||||
username = path.substring(1, if (firstSlashIndex == -1) path.length else firstSlashIndex)
|
||||
}
|
||||
|
||||
val authenticationForm = RepositoryAuthenticationForm(if (sshKeyFile == null) {
|
||||
icsMessage("log.in.to", StringUtil.trimMiddle(uri, 50))
|
||||
val message = if (sshKeyFile == null) icsMessage("log.in.to", uri.trimMiddle(50)) else icsMessage("enter.your.password.for.ssh.key", PathUtilRt.getFileName(sshKeyFile))
|
||||
|
||||
return UIUtil.invokeAndWaitIfNeeded(Computable {
|
||||
val userField = JTextField(username)
|
||||
val passwordField = JPasswordField(credentials?.password)
|
||||
|
||||
val centerPanel = panel(fillX) {
|
||||
label(message, wrap, span, bold = true, gapBottom = 10)
|
||||
|
||||
if (sshKeyFile == null && !isGitHub) {
|
||||
label("Username:")
|
||||
userField(grow, wrap)
|
||||
}
|
||||
|
||||
label(if (sshKeyFile == null && isGitHub) "Token:" else "Password:")
|
||||
passwordField(grow, wrap)
|
||||
|
||||
note?.let { noteComponent(it)(skip) }
|
||||
}
|
||||
else {
|
||||
icsMessage("enter.your.password.for.ssh.key", PathUtilRt.getFileName(sshKeyFile))
|
||||
}, username, credentials?.token, note, sshKeyFile != null)
|
||||
|
||||
val authenticationForm = dialog(
|
||||
title = "Settings Repository",
|
||||
resizable = false,
|
||||
centerPanel = centerPanel,
|
||||
preferedFocusComponent = userField,
|
||||
okActionEnabled = false)
|
||||
|
||||
passwordField.document.addDocumentListener(object : DocumentAdapter() {
|
||||
override fun textChanged(e: DocumentEvent) {
|
||||
authenticationForm.okActionEnabled(e.document.length != 0)
|
||||
}
|
||||
})
|
||||
authenticationForm.okActionEnabled(false)
|
||||
|
||||
if (authenticationForm.showAndGet()) {
|
||||
username = sshKeyFile ?: authenticationForm.username
|
||||
val passwordChars = authenticationForm.password
|
||||
Credentials(username, if (passwordChars == null) (if (username == null) null else "x-oauth-basic") else String(passwordChars))
|
||||
username = sshKeyFile ?: userField.text.nullize(true)
|
||||
val passwordChars = passwordField.password
|
||||
Credentials(username, if (passwordChars == null || passwordChars.isEmpty()) (if (username == null) null else "x-oauth-basic") else String(passwordChars))
|
||||
}
|
||||
else {
|
||||
null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun noteComponent(note: String): SimpleColoredComponent {
|
||||
val noteComponent = SimpleColoredComponent()
|
||||
|
||||
val matcher = HREF_PATTERN.matcher(note)
|
||||
var prev = 0
|
||||
if (matcher.find()) {
|
||||
do {
|
||||
if (matcher.start() != prev) {
|
||||
noteComponent.append(note.substring(prev, matcher.start()), SMALL_TEXT_ATTRIBUTES)
|
||||
}
|
||||
noteComponent.append(matcher.group(2), LINK_TEXT_ATTRIBUTES, SimpleColoredComponent.BrowserLauncherTag(matcher.group(1)))
|
||||
prev = matcher.end()
|
||||
}
|
||||
while (matcher.find())
|
||||
|
||||
LinkMouseListenerBase.installSingleTagOn(noteComponent)
|
||||
}
|
||||
|
||||
if (prev < note.length) {
|
||||
noteComponent.append(note.substring(prev), SMALL_TEXT_ATTRIBUTES)
|
||||
}
|
||||
|
||||
return noteComponent
|
||||
}
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.jetbrains.settingsRepository.git
|
||||
|
||||
import com.intellij.credentialStore.Credentials
|
||||
import com.intellij.credentialStore.isFulfilled
|
||||
import com.intellij.credentialStore.macOs.isMacOsCredentialStoreSupported
|
||||
import com.intellij.openapi.ui.MessageDialogBuilder
|
||||
import com.intellij.openapi.ui.Messages
|
||||
@@ -25,9 +27,7 @@ import org.eclipse.jgit.lib.Repository
|
||||
import org.eclipse.jgit.transport.CredentialItem
|
||||
import org.eclipse.jgit.transport.CredentialsProvider
|
||||
import org.eclipse.jgit.transport.URIish
|
||||
import org.jetbrains.keychain.Credentials
|
||||
import org.jetbrains.keychain.CredentialsStore
|
||||
import org.jetbrains.keychain.isFulfilled
|
||||
import org.jetbrains.settingsRepository.LOG
|
||||
import org.jetbrains.settingsRepository.showAuthenticationForm
|
||||
|
||||
@@ -116,10 +116,10 @@ class JGitCredentialsProvider(private val credentialsStore: NotNullLazyValue<Cre
|
||||
|
||||
if (userFromUri != null) {
|
||||
// username is in url - read password only if it is for the same user
|
||||
if (userFromUri != credentials?.id) {
|
||||
if (userFromUri != credentials?.user) {
|
||||
credentials = Credentials(userFromUri, passwordFromUri)
|
||||
}
|
||||
else if (passwordFromUri != null && passwordFromUri != credentials?.token) {
|
||||
else if (passwordFromUri != null && passwordFromUri != credentials?.password) {
|
||||
credentials = Credentials(userFromUri, passwordFromUri)
|
||||
}
|
||||
}
|
||||
@@ -134,13 +134,13 @@ class JGitCredentialsProvider(private val credentialsStore: NotNullLazyValue<Cre
|
||||
credentialsStore.value.save(uri.host, credentials!!, sshKeyFile)
|
||||
}
|
||||
|
||||
userNameItem?.value = credentials?.id
|
||||
userNameItem?.value = credentials?.user
|
||||
if (passwordItem != null) {
|
||||
if (passwordItem is CredentialItem.Password) {
|
||||
passwordItem.value = credentials?.token?.toCharArray()
|
||||
passwordItem.value = credentials?.password?.toCharArray()
|
||||
}
|
||||
else {
|
||||
(passwordItem as CredentialItem.StringType).value = credentials?.token
|
||||
(passwordItem as CredentialItem.StringType).value = credentials?.password
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,12 +15,12 @@
|
||||
*/
|
||||
package org.jetbrains.settingsRepository.git
|
||||
|
||||
import com.intellij.credentialStore.Credentials
|
||||
import com.intellij.execution.configurations.GeneralCommandLine
|
||||
import com.intellij.execution.process.ProcessNotCreatedException
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.eclipse.jgit.lib.Repository
|
||||
import org.eclipse.jgit.transport.URIish
|
||||
import org.jetbrains.keychain.Credentials
|
||||
import org.jetbrains.settingsRepository.LOG
|
||||
|
||||
private var canUseGitExe = true
|
||||
|
||||
@@ -15,26 +15,11 @@
|
||||
*/
|
||||
package org.jetbrains.keychain
|
||||
|
||||
import com.intellij.credentialStore.Credentials
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
|
||||
val LOG: Logger = Logger.getInstance(CredentialsStore::class.java)
|
||||
|
||||
class Credentials(id: String?, token: String?) {
|
||||
val id: String? = if (id.isNullOrEmpty()) null else id
|
||||
val token: String? = if (token.isNullOrEmpty()) null else token
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is Credentials) return false
|
||||
return id == other.id && token == other.token
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return (id?.hashCode() ?: 0) * 37 + (token?.hashCode() ?: 0)
|
||||
}
|
||||
}
|
||||
|
||||
fun Credentials?.isFulfilled(): Boolean = this != null && id != null && token != null
|
||||
|
||||
interface CredentialsStore {
|
||||
fun get(host: String?, sshKeyFile: String? = null): Credentials?
|
||||
|
||||
|
||||
@@ -15,8 +15,9 @@
|
||||
*/
|
||||
package org.jetbrains.keychain
|
||||
|
||||
import com.intellij.credentialStore.Credentials
|
||||
import com.intellij.credentialStore.splitData
|
||||
import com.intellij.ide.passwordSafe.PasswordSafe
|
||||
import com.intellij.openapi.util.PasswordUtil
|
||||
|
||||
class FileCredentialsStore() : CredentialsStore {
|
||||
override fun get(host: String?, sshKeyFile: String?): Credentials? {
|
||||
@@ -24,22 +25,13 @@ class FileCredentialsStore() : CredentialsStore {
|
||||
return null
|
||||
}
|
||||
|
||||
val accountName = sshKeyFile ?: host
|
||||
|
||||
val data = PasswordSafe.getInstance().getPassword("ics-" + accountName) ?: return null
|
||||
val data = PasswordSafe.getInstance().getPassword("ics-" + (sshKeyFile ?: host)) ?: return null
|
||||
if (sshKeyFile == null) {
|
||||
val separatorIndex = data.indexOf('@')
|
||||
if (separatorIndex > 0) {
|
||||
val username = PasswordUtil.decodePassword(data.substring(0, separatorIndex))
|
||||
val password = PasswordUtil.decodePassword(data.substring(separatorIndex + 1))
|
||||
return Credentials(username, password)
|
||||
}
|
||||
return splitData(data)
|
||||
}
|
||||
else {
|
||||
return Credentials(sshKeyFile, data)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
override fun reset(host: String) {
|
||||
@@ -48,6 +40,6 @@ class FileCredentialsStore() : CredentialsStore {
|
||||
|
||||
override fun save(host: String?, credentials: Credentials, sshKeyFile: String?) {
|
||||
val accountName: String = sshKeyFile ?: host!!
|
||||
PasswordSafe.getInstance().setPassword("ics-" + accountName, if (sshKeyFile == null) "${PasswordUtil.encodePassword(credentials.id)}@${PasswordUtil.encodePassword(credentials.token)}" else credentials.token!!)
|
||||
PasswordSafe.getInstance().setPassword("ics-" + accountName, if (sshKeyFile == null) credentials.toString() else credentials.password!!)
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.jetbrains.keychain
|
||||
|
||||
import com.intellij.credentialStore.Credentials
|
||||
import com.intellij.credentialStore.macOs.deleteGenericPassword
|
||||
import com.intellij.credentialStore.macOs.findGenericPassword
|
||||
import com.intellij.credentialStore.macOs.saveGenericPassword
|
||||
@@ -74,7 +75,7 @@ class OsXCredentialsStore(serviceName: String) : CredentialsStore {
|
||||
return
|
||||
}
|
||||
|
||||
val data = if (sshKeyFile == null) "${PasswordUtil.encodePassword(credentials.id)}@${PasswordUtil.encodePassword(credentials.token)}" else credentials.token!!
|
||||
val data = if (sshKeyFile == null) credentials.toString() else credentials.password!!
|
||||
saveGenericPassword(getServiceName(sshKeyFile), accountName, data.toByteArray())
|
||||
}
|
||||
|
||||
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.settingsRepository.RepositoryAuthenticationForm">
|
||||
<grid id="27dc6" binding="panel" layout-manager="GridLayoutManager" row-count="5" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="500" height="400"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<vspacer id="2584d">
|
||||
<constraints>
|
||||
<grid row="4" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</vspacer>
|
||||
<component id="c57ee" class="javax.swing.JTextField" binding="tokenField">
|
||||
<constraints>
|
||||
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="150" height="-1"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="5dcc7" class="javax.swing.JLabel" binding="tokenLabel">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<labelFor value="c57ee"/>
|
||||
<text value="Username:"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="f995c" class="javax.swing.JLabel">
|
||||
<constraints>
|
||||
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<labelFor value="4cb05"/>
|
||||
<text value="Password:"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="4cb05" class="javax.swing.JPasswordField" binding="passwordField">
|
||||
<constraints>
|
||||
<grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false">
|
||||
<preferred-size width="150" height="-1"/>
|
||||
</grid>
|
||||
</constraints>
|
||||
<properties/>
|
||||
</component>
|
||||
<component id="6db40" class="com.intellij.ui.SimpleColoredComponent" binding="noteComponent">
|
||||
<constraints>
|
||||
<grid row="3" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<ipad top="5" left="2" bottom="1" right="2"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="7ab68" class="javax.swing.JLabel" binding="messageLabel">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<enabled value="true"/>
|
||||
<font style="1"/>
|
||||
<text value="Message"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
-111
@@ -1,111 +0,0 @@
|
||||
package org.jetbrains.settingsRepository;
|
||||
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vcs.changes.issueLinks.LinkMouseListenerBase;
|
||||
import com.intellij.ui.DocumentAdapter;
|
||||
import com.intellij.ui.JBColor;
|
||||
import com.intellij.ui.SimpleColoredComponent;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
final class RepositoryAuthenticationForm extends DialogWrapper {
|
||||
private static final Pattern HREF_PATTERN = Pattern.compile("<a(?:\\s+href\\s*=\\s*[\"']([^\"']*)[\"'])?\\s*>([^<]*)</a>");
|
||||
|
||||
private static final SimpleTextAttributes LINK_TEXT_ATTRIBUTES = new SimpleTextAttributes(SimpleTextAttributes.STYLE_SMALLER, JBColor.blue);
|
||||
private static final SimpleTextAttributes SMALL_TEXT_ATTRIBUTES = new SimpleTextAttributes(SimpleTextAttributes.STYLE_SMALLER, null);
|
||||
|
||||
private JTextField tokenField;
|
||||
private SimpleColoredComponent noteComponent;
|
||||
private JPasswordField passwordField;
|
||||
|
||||
private JPanel panel;
|
||||
private JLabel tokenLabel;
|
||||
private JLabel messageLabel;
|
||||
|
||||
private final JComponent initialFocusedComponent;
|
||||
|
||||
public RepositoryAuthenticationForm(@NotNull String message, @Nullable String token, @Nullable String password, @Nullable String note, boolean onlyPassword) {
|
||||
super(false);
|
||||
|
||||
setTitle("Settings Repository");
|
||||
setResizable(false);
|
||||
|
||||
messageLabel.setText(message);
|
||||
messageLabel.setBorder(new EmptyBorder(0, 0, 10, 0));
|
||||
|
||||
if (onlyPassword) {
|
||||
tokenLabel.setVisible(false);
|
||||
tokenField.setVisible(false);
|
||||
|
||||
passwordField.getDocument().addDocumentListener(new DocumentAdapter() {
|
||||
@Override
|
||||
protected void textChanged(DocumentEvent e) {
|
||||
setOKActionEnabled(e.getDocument().getLength() != 0);
|
||||
}
|
||||
});
|
||||
initialFocusedComponent = passwordField;
|
||||
setOKActionEnabled(false);
|
||||
}
|
||||
else {
|
||||
tokenField.setText(token);
|
||||
passwordField.setText(password);
|
||||
initialFocusedComponent = StringUtil.isEmpty(token) ? tokenField : passwordField;
|
||||
}
|
||||
|
||||
if (note == null) {
|
||||
noteComponent.setVisible(false);
|
||||
}
|
||||
else {
|
||||
Matcher matcher = HREF_PATTERN.matcher(note);
|
||||
int prev = 0;
|
||||
if (matcher.find()) {
|
||||
do {
|
||||
if (matcher.start() != prev) {
|
||||
noteComponent.append(note.substring(prev, matcher.start()), SMALL_TEXT_ATTRIBUTES);
|
||||
}
|
||||
noteComponent.append(matcher.group(2), LINK_TEXT_ATTRIBUTES, new SimpleColoredComponent.BrowserLauncherTag(matcher.group(1)));
|
||||
prev = matcher.end();
|
||||
}
|
||||
while (matcher.find());
|
||||
|
||||
LinkMouseListenerBase.installSingleTagOn(noteComponent);
|
||||
}
|
||||
|
||||
if (prev < note.length()) {
|
||||
noteComponent.append(note.substring(prev), SMALL_TEXT_ATTRIBUTES);
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
return initialFocusedComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
return panel;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getUsername() {
|
||||
return StringUtil.nullize(tokenField.getText(), true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public char[] getPassword() {
|
||||
char[] chars = passwordField.getPassword();
|
||||
return chars == null || chars.length == 0 ? null : chars;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
package org.jetbrains.settingsRepository.test
|
||||
|
||||
import com.intellij.credentialStore.Credentials
|
||||
import com.intellij.openapi.util.NotNullLazyValue
|
||||
import com.intellij.testFramework.ApplicationRule
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.eclipse.jgit.storage.file.FileRepositoryBuilder
|
||||
import org.eclipse.jgit.transport.CredentialItem
|
||||
import org.eclipse.jgit.transport.URIish
|
||||
import org.jetbrains.keychain.Credentials
|
||||
import org.jetbrains.keychain.CredentialsStore
|
||||
import org.jetbrains.keychain.FileCredentialsStore
|
||||
import org.jetbrains.settingsRepository.git.JGitCredentialsProvider
|
||||
|
||||
Reference in New Issue
Block a user