fix: preserve oauth state and verify emails
diff --git a/connector-apache/apache.go b/connector-apache/apache.go
index 6d97b4c..8107202 100644
--- a/connector-apache/apache.go
+++ b/connector-apache/apache.go
@@ -70,7 +70,10 @@
 }
 
 func (g *Connector) ConnectorSender(ctx *plugin.GinContext, receiverURL string) (redirectURL string) {
-	state := token.GenerateToken()
+	state := ctx.Query("state")
+	if len(state) == 0 {
+		state = token.GenerateToken()
+	}
 	return fmt.Sprintf("https://oauth.apache.org/auth?state=%s&redirect_uri=%s", state, receiverURL)
 }
 
diff --git a/connector-basic/basic.go b/connector-basic/basic.go
index 2dadea2..b021325 100644
--- a/connector-basic/basic.go
+++ b/connector-basic/basic.go
@@ -84,7 +84,7 @@
 
 func init() {
 	plugin.Register(&Connector{
-		Config: &ConnectorConfig{},
+		Config: &ConnectorConfig{CheckEmailVerified: true},
 	})
 }
 
@@ -128,7 +128,10 @@
 		RedirectURL: receiverURL,
 		Scopes:      strings.Split(g.Config.Scope, ","),
 	}
-	state := randomString(24)
+	state := ctx.Query("state")
+	if len(state) == 0 {
+		state = randomString(24)
+	}
 	return oauth2Config.AuthCodeURL(state)
 }
 
@@ -183,10 +186,14 @@
 	if len(g.Config.UserEmailJsonPath) > 0 {
 		userInfo.Email = gjson.GetBytes(data, g.Config.UserEmailJsonPath).String()
 	}
-	if g.Config.CheckEmailVerified && len(g.Config.EmailVerifiedJsonPath) > 0 {
-		emailVerified := gjson.GetBytes(data, g.Config.EmailVerifiedJsonPath).Bool()
-		if !emailVerified {
+	if g.Config.CheckEmailVerified {
+		if len(g.Config.EmailVerifiedJsonPath) == 0 {
 			userInfo.Email = ""
+		} else {
+			emailVerified := gjson.GetBytes(data, g.Config.EmailVerifiedJsonPath).Bool()
+			if !emailVerified {
+				userInfo.Email = ""
+			}
 		}
 	}
 	if len(g.Config.UserAvatarJsonPath) > 0 {
@@ -273,6 +280,11 @@
 func (g *Connector) ConfigReceiver(config []byte) error {
 	c := &ConnectorConfig{}
 	_ = json.Unmarshal(config, c)
+	conf := map[string]any{}
+	_ = json.Unmarshal(config, &conf)
+	if _, ok := conf["check_email_verified"]; !ok {
+		c.CheckEmailVerified = true
+	}
 	g.Config = c
 	return nil
 }
diff --git a/connector-dingtalk/dingtalk.go b/connector-dingtalk/dingtalk.go
index 5f7d569..f1ec0de 100644
--- a/connector-dingtalk/dingtalk.go
+++ b/connector-dingtalk/dingtalk.go
@@ -101,8 +101,12 @@
 }
 
 func (g *Connector) ConnectorSender(ctx *plugin.GinContext, receiverURL string) (redirectURL string) {
-	return fmt.Sprintf("%s?redirect_uri=%s&response_type=code&client_id=%s&scope=Contact.User.Read&state=state&prompt=consent",
-		AuthorizeURL, receiverURL, g.Config.ClientID)
+	state := ctx.Query("state")
+	if len(state) == 0 {
+		state = "state"
+	}
+	return fmt.Sprintf("%s?redirect_uri=%s&response_type=code&client_id=%s&scope=Contact.User.Read&state=%s&prompt=consent",
+		AuthorizeURL, receiverURL, g.Config.ClientID, state)
 }
 
 func (g *Connector) ConnectorReceiver(ctx *plugin.GinContext, receiverURL string) (userInfo plugin.ExternalLoginUserInfo, err error) {
diff --git a/connector-github/github.go b/connector-github/github.go
index fddb34c..06ca014 100644
--- a/connector-github/github.go
+++ b/connector-github/github.go
@@ -87,7 +87,11 @@
 		RedirectURL:  receiverURL,
 		Scopes:       []string{"user:email"},
 	}
-	return oauth2Config.AuthCodeURL("state")
+	state := ctx.Query("state")
+	if len(state) == 0 {
+		state = "state"
+	}
+	return oauth2Config.AuthCodeURL(state)
 }
 
 func (g *Connector) ConnectorReceiver(ctx *plugin.GinContext, receiverURL string) (userInfo plugin.ExternalLoginUserInfo, err error) {
@@ -142,7 +146,7 @@
 		return ""
 	}
 	for _, e := range emails {
-		if e.GetPrimary() {
+		if e.GetPrimary() && e.GetVerified() {
 			return e.GetEmail()
 		}
 	}
diff --git a/connector-google/google.go b/connector-google/google.go
index 1cefb7a..11c9bcf 100644
--- a/connector-google/google.go
+++ b/connector-google/google.go
@@ -102,7 +102,11 @@
 			"openid",
 		},
 	}
-	return oauth2Config.AuthCodeURL("state")
+	state := ctx.Query("state")
+	if len(state) == 0 {
+		state = "state"
+	}
+	return oauth2Config.AuthCodeURL(state)
 }
 
 func (g *Connector) ConnectorReceiver(ctx *plugin.GinContext, receiverURL string) (userInfo plugin.ExternalLoginUserInfo, err error) {
diff --git a/connector-wallet/WalletAuthorizer.tsx b/connector-wallet/WalletAuthorizer.tsx
index 4436620..fb52089 100644
--- a/connector-wallet/WalletAuthorizer.tsx
+++ b/connector-wallet/WalletAuthorizer.tsx
@@ -62,8 +62,10 @@
         const handleAuthorize = async () => {
           const nonce = getSearchParamValue('nonce', sha256(address));
           const signature = await signMessageAsync({ message: nonce });
+          const state = getSearchParamValue('state');
+          const stateParam = state ? `&state=${encodeURIComponent(state)}` : '';
 
-          location.href = `/answer/api/v1/connector/redirect/wallet?message=${nonce}&signature=${signature}&address=${address}&redirect=${getSearchParamValue('redirect')}`;
+          location.href = `/answer/api/v1/connector/redirect/wallet?message=${nonce}&signature=${signature}&address=${address}&redirect=${getSearchParamValue('redirect')}${stateParam}`;
         }
 
         return (
diff --git a/connector-wallet/wallet.go b/connector-wallet/wallet.go
index d6e1b83..9dc4776 100644
--- a/connector-wallet/wallet.go
+++ b/connector-wallet/wallet.go
@@ -22,6 +22,7 @@
 import (
 	"embed"
 	"fmt"
+	"net/url"
 	"strconv"
 	"time"
 
@@ -81,6 +82,9 @@
 func (g *Connector) ConnectorSender(ctx *plugin.GinContext, receiverURL string) (redirectURL string) {
 	randomString := fmt.Sprintf("%d", time.Now().Unix()) + generateRandomString(8)
 	redirectURL = "/connector-wallet-auth" + "?nonce=" + randomString
+	if state := ctx.Query("state"); len(state) > 0 {
+		redirectURL += "&state=" + url.QueryEscape(state)
+	}
 	return redirectURL
 }