mirror of
https://github.com/casdoor/casdoor.git
synced 2025-05-23 02:35:49 +08:00
feat: support Web3-Onboard provider (#2209)
* feat: add Web3-Onboard idp * feat: update Web3-Onboard logo * feat: update package.json * feat: remove unused package * feat: add yarn build param --max_old_space_size=4096 * feat: remove log * feat: add Wallet configure * feat: remove hardware wallets
This commit is contained in:
parent
80b0d26813
commit
891e8e21d8
@ -24,20 +24,10 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const Web3AuthTokenKey = "web3AuthToken"
|
||||
|
||||
type MetaMaskIdProvider struct {
|
||||
Client *http.Client
|
||||
}
|
||||
|
||||
type Web3AuthToken struct {
|
||||
Address string `json:"address"`
|
||||
Nonce string `json:"nonce"`
|
||||
CreateAt uint64 `json:"createAt"`
|
||||
TypedData string `json:"typedData"`
|
||||
Signature string `json:"signature"` // signature for typed data
|
||||
}
|
||||
|
||||
func NewMetaMaskIdProvider() *MetaMaskIdProvider {
|
||||
idp := &MetaMaskIdProvider{}
|
||||
return idp
|
||||
|
@ -111,6 +111,8 @@ func GetIdProvider(idpInfo *ProviderInfo, redirectUrl string) IdProvider {
|
||||
return NewBilibiliIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
|
||||
case "MetaMask":
|
||||
return NewMetaMaskIdProvider()
|
||||
case "Web3Onboard":
|
||||
return NewWeb3OnboardIdProvider()
|
||||
default:
|
||||
if isGothSupport(idpInfo.Type) {
|
||||
return NewGothIdProvider(idpInfo.Type, idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl, idpInfo.HostUrl)
|
||||
|
103
idp/web3onboard.go
Normal file
103
idp/web3onboard.go
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package idp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const Web3AuthTokenKey = "web3AuthToken"
|
||||
|
||||
type Web3AuthToken struct {
|
||||
Address string `json:"address"`
|
||||
Nonce string `json:"nonce"`
|
||||
CreateAt uint64 `json:"createAt"`
|
||||
TypedData string `json:"typedData"` // typed data use for application
|
||||
Signature string `json:"signature"` // signature for typed data
|
||||
WalletType string `json:"walletType"` // e.g."MetaMask", "Coinbase"
|
||||
}
|
||||
|
||||
type Web3OnboardIdProvider struct {
|
||||
Client *http.Client
|
||||
}
|
||||
|
||||
func NewWeb3OnboardIdProvider() *Web3OnboardIdProvider {
|
||||
idp := &Web3OnboardIdProvider{}
|
||||
return idp
|
||||
}
|
||||
|
||||
func (idp *Web3OnboardIdProvider) SetHttpClient(client *http.Client) {
|
||||
idp.Client = client
|
||||
}
|
||||
|
||||
func (idp *Web3OnboardIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
web3AuthToken := Web3AuthToken{}
|
||||
if err := json.Unmarshal([]byte(code), &web3AuthToken); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
token := &oauth2.Token{
|
||||
AccessToken: fmt.Sprintf("%v:%v", Web3AuthTokenKey, web3AuthToken.Address),
|
||||
TokenType: "Bearer",
|
||||
Expiry: time.Now().AddDate(0, 1, 0),
|
||||
}
|
||||
|
||||
token = token.WithExtra(map[string]interface{}{
|
||||
Web3AuthTokenKey: web3AuthToken,
|
||||
})
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (idp *Web3OnboardIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
web3AuthToken, ok := token.Extra(Web3AuthTokenKey).(Web3AuthToken)
|
||||
if !ok {
|
||||
return nil, errors.New("invalid web3AuthToken")
|
||||
}
|
||||
|
||||
fmtAddress := fmt.Sprintf("%v_%v",
|
||||
strings.ReplaceAll(strings.TrimSpace(web3AuthToken.WalletType), " ", "_"),
|
||||
web3AuthToken.Address,
|
||||
)
|
||||
userInfo := &UserInfo{
|
||||
Id: fmtAddress,
|
||||
Username: fmtAddress,
|
||||
DisplayName: fmtAddress,
|
||||
AvatarUrl: fmt.Sprintf("metamask:%v", forceEthereumAddress(web3AuthToken.Address)),
|
||||
}
|
||||
return userInfo, nil
|
||||
}
|
||||
|
||||
func forceEthereumAddress(address string) string {
|
||||
// The required address to general MetaMask avatar is a string of length 42 that represents an Ethereum address.
|
||||
// This function is used to force any address as an Ethereum address
|
||||
address = strings.TrimSpace(address)
|
||||
var builder strings.Builder
|
||||
for _, ch := range address {
|
||||
builder.WriteRune(ch)
|
||||
}
|
||||
for len(builder.String()) < 42 {
|
||||
builder.WriteString("0")
|
||||
}
|
||||
if len(builder.String()) > 42 {
|
||||
return builder.String()[:42]
|
||||
}
|
||||
return builder.String()
|
||||
}
|
@ -170,6 +170,7 @@ type User struct {
|
||||
Yandex string `xorm:"yandex varchar(100)" json:"yandex"`
|
||||
Zoom string `xorm:"zoom varchar(100)" json:"zoom"`
|
||||
MetaMask string `xorm:"metamask varchar(100)" json:"metamask"`
|
||||
Web3Onboard string `xorm:"web3onboard varchar(100)" json:"web3onboard"`
|
||||
Custom string `xorm:"custom varchar(100)" json:"custom"`
|
||||
|
||||
WebauthnCredentials []webauthn.Credential `xorm:"webauthnCredentials blob" json:"webauthnCredentials"`
|
||||
|
@ -51,31 +51,46 @@ module.exports = {
|
||||
},
|
||||
],
|
||||
webpack: {
|
||||
// use polyfill Buffer with Webpack 5
|
||||
// https://viglucci.io/articles/how-to-polyfill-buffer-with-webpack-5
|
||||
// https://craco.js.org/docs/configuration/webpack/
|
||||
configure: (webpackConfig, { env, paths }) => {
|
||||
webpackConfig.resolve.fallback = {
|
||||
// "process": require.resolve('process/browser'),
|
||||
// "util": require.resolve("util/"),
|
||||
// "url": require.resolve("url/"),
|
||||
// "zlib": require.resolve("browserify-zlib"),
|
||||
// "stream": require.resolve("stream-browserify"),
|
||||
// "http": require.resolve("stream-http"),
|
||||
// "https": require.resolve("https-browserify"),
|
||||
// "assert": require.resolve("assert/"),
|
||||
"buffer": require.resolve('buffer/'),
|
||||
"process": false,
|
||||
"util": false,
|
||||
"url": false,
|
||||
"zlib": false,
|
||||
"stream": false,
|
||||
"http": false,
|
||||
"https": false,
|
||||
"assert": false,
|
||||
"buffer": false,
|
||||
};
|
||||
return webpackConfig;
|
||||
configure: {
|
||||
// ignore webpack warnings by source-map-loader
|
||||
// https://github.com/facebook/create-react-app/pull/11752#issuecomment-1345231546
|
||||
ignoreWarnings: [
|
||||
function ignoreSourcemapsloaderWarnings(warning) {
|
||||
return (
|
||||
warning.module &&
|
||||
warning.module.resource.includes('node_modules') &&
|
||||
warning.details &&
|
||||
warning.details.includes('source-map-loader')
|
||||
)
|
||||
},
|
||||
],
|
||||
// use polyfill Buffer with Webpack 5
|
||||
// https://viglucci.io/articles/how-to-polyfill-buffer-with-webpack-5
|
||||
// https://craco.js.org/docs/configuration/webpack/
|
||||
resolve: {
|
||||
fallback: {
|
||||
// "process": require.resolve('process/browser'),
|
||||
// "util": require.resolve("util/"),
|
||||
// "url": require.resolve("url/"),
|
||||
// "zlib": require.resolve("browserify-zlib"),
|
||||
// "stream": require.resolve("stream-browserify"),
|
||||
// "http": require.resolve("stream-http"),
|
||||
// "https": require.resolve("https-browserify"),
|
||||
// "assert": require.resolve("assert/"),
|
||||
"buffer": require.resolve('buffer/'),
|
||||
"process": false,
|
||||
"util": false,
|
||||
"url": false,
|
||||
"zlib": false,
|
||||
"stream": false,
|
||||
"http": false,
|
||||
"https": false,
|
||||
"assert": false,
|
||||
"buffer": false,
|
||||
"crypto": false,
|
||||
"os": false,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
|
@ -13,6 +13,16 @@
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.3.2",
|
||||
"@testing-library/user-event": "^7.1.2",
|
||||
"@web3-onboard/coinbase": "^2.2.5",
|
||||
"@web3-onboard/core": "^2.20.5",
|
||||
"@web3-onboard/frontier": "^2.0.4",
|
||||
"@web3-onboard/gnosis": "^2.1.10",
|
||||
"@web3-onboard/infinity-wallet": "^2.0.4",
|
||||
"@web3-onboard/injected-wallets": "^2.10.4",
|
||||
"@web3-onboard/react": "^2.8.10",
|
||||
"@web3-onboard/sequence": "^2.0.8",
|
||||
"@web3-onboard/taho": "^2.0.5",
|
||||
"@web3-onboard/trust": "^2.0.4",
|
||||
"antd": "5.2.3",
|
||||
"antd-token-previewer": "^1.1.0-22",
|
||||
"buffer": "^6.0.3",
|
||||
@ -21,6 +31,7 @@
|
||||
"core-js": "^3.25.0",
|
||||
"craco-less": "^2.0.0",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"ethers": "5.6.9",
|
||||
"file-saver": "^2.0.5",
|
||||
"i18n-iso-countries": "^7.0.0",
|
||||
"i18next": "^19.8.9",
|
||||
@ -44,7 +55,7 @@
|
||||
},
|
||||
"scripts": {
|
||||
"start": "cross-env PORT=7001 craco start",
|
||||
"build": "craco build",
|
||||
"build": "craco --max_old_space_size=4096 build",
|
||||
"test": "craco test",
|
||||
"eject": "craco eject",
|
||||
"crowdin:sync": "crowdin upload && crowdin download",
|
||||
|
@ -351,7 +351,7 @@ class App extends Component {
|
||||
}
|
||||
|
||||
|
||||
{Setting.isMobile() ? null : Setting.getNameAtLeast(this.state.account.displayName)} <DownOutlined />
|
||||
{Setting.isMobile() ? null : Setting.getShortText(Setting.getNameAtLeast(this.state.account.displayName), 30)} <DownOutlined />
|
||||
|
||||
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import {Button, Card, Col, Input, InputNumber, Row, Select, Switch} from "antd";
|
||||
import {Button, Card, Checkbox, Col, Input, InputNumber, Row, Select, Switch} from "antd";
|
||||
import {LinkOutlined} from "@ant-design/icons";
|
||||
import * as ProviderBackend from "./backend/ProviderBackend";
|
||||
import * as Setting from "./Setting";
|
||||
@ -25,6 +25,7 @@ import copy from "copy-to-clipboard";
|
||||
import {CaptchaPreview} from "./common/CaptchaPreview";
|
||||
import * as OrganizationBackend from "./backend/OrganizationBackend";
|
||||
import {CountryCodeSelect} from "./common/select/CountryCodeSelect";
|
||||
import * as Web3Auth from "./auth/Web3Auth";
|
||||
|
||||
const {Option} = Select;
|
||||
const {TextArea} = Input;
|
||||
@ -1011,6 +1012,30 @@ class ProviderEditPage extends React.Component {
|
||||
</Row>
|
||||
) : null
|
||||
}
|
||||
{
|
||||
this.state.provider.type === "Web3Onboard" ? (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Wallets"), i18next.t("provider:Wallets - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<Checkbox.Group
|
||||
options={Web3Auth.getWeb3OnboardWalletsOptions()}
|
||||
value={() => {
|
||||
try {
|
||||
return JSON.parse(this.state.provider.metadata);
|
||||
} catch {
|
||||
return ["injected"];
|
||||
}
|
||||
}}
|
||||
onChange={options => {
|
||||
this.updateProviderField("metadata", JSON.stringify(options));
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
) : null
|
||||
}
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Provider URL"), i18next.t("provider:Provider URL - Tooltip"))} :
|
||||
|
@ -259,6 +259,10 @@ export const OtherProviderInfo = {
|
||||
logo: `${StaticBaseUrl}/img/social_metamask.svg`,
|
||||
url: "https://metamask.io/",
|
||||
},
|
||||
"Web3Onboard": {
|
||||
logo: `${StaticBaseUrl}/img/social_web3onboard.svg`,
|
||||
url: "https://onboard.blocknative.com/",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -943,6 +947,7 @@ export function getProviderTypeOptions(category) {
|
||||
} else if (category === "Web3") {
|
||||
return ([
|
||||
{id: "MetaMask", name: "MetaMask"},
|
||||
{id: "Web3Onboard", name: "Web3-Onboard"},
|
||||
]);
|
||||
} else {
|
||||
return [];
|
||||
|
@ -95,7 +95,7 @@ class AuthCallback extends React.Component {
|
||||
if (code === null) {
|
||||
code = params.get("authCode");
|
||||
}
|
||||
// The code for Metamask is the JSON-serialized string of Web3AuthToken
|
||||
// The code for Web3 is the JSON-serialized string of Web3AuthToken
|
||||
// Due to the limited length of URLs, we only pass the web3AuthTokenKey
|
||||
if (code === null) {
|
||||
code = params.get("web3AuthTokenKey");
|
||||
|
@ -321,6 +321,10 @@ const authInfo = {
|
||||
scope: "",
|
||||
endpoint: "",
|
||||
},
|
||||
Web3Onboard: {
|
||||
scope: "",
|
||||
endpoint: "",
|
||||
},
|
||||
};
|
||||
|
||||
export function getProviderUrl(provider) {
|
||||
@ -465,5 +469,7 @@ export function getAuthUrl(application, provider, method) {
|
||||
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&code_challenge=${codeChallenge}&code_challenge_method=S256`;
|
||||
} else if (provider.type === "MetaMask") {
|
||||
return `${redirectUri}?state=${state}`;
|
||||
} else if (provider.type === "Web3Onboard") {
|
||||
return `${redirectUri}?state=${state}`;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import i18next from "i18next";
|
||||
import * as Provider from "./Provider";
|
||||
import {getProviderLogoURL} from "../Setting";
|
||||
import {GithubLoginButton, GoogleLoginButton} from "react-social-login-buttons";
|
||||
import {authViaMetaMask} from "./Web3Auth";
|
||||
import {authViaMetaMask, authViaWeb3Onboard} from "./Web3Auth";
|
||||
import QqLoginButton from "./QqLoginButton";
|
||||
import FacebookLoginButton from "./FacebookLoginButton";
|
||||
import WeiboLoginButton from "./WeiboLoginButton";
|
||||
@ -121,6 +121,8 @@ function goToSamlUrl(provider, location) {
|
||||
export function goToWeb3Url(application, provider, method) {
|
||||
if (provider.type === "MetaMask") {
|
||||
authViaMetaMask(application, provider, method);
|
||||
} else if (provider.type === "Web3Onboard") {
|
||||
authViaWeb3Onboard(application, provider, method);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,25 @@ import {v4 as uuidv4} from "uuid";
|
||||
import {SignTypedDataVersion, recoverTypedSignature} from "@metamask/eth-sig-util";
|
||||
import {getAuthUrl} from "./Provider";
|
||||
import {Buffer} from "buffer";
|
||||
// import {toChecksumAddress} from "ethereumjs-util";
|
||||
import Onboard from "@web3-onboard/core";
|
||||
import injectedModule from "@web3-onboard/injected-wallets";
|
||||
import infinityWalletModule from "@web3-onboard/infinity-wallet";
|
||||
import sequenceModule from "@web3-onboard/sequence";
|
||||
import trustModule from "@web3-onboard/trust";
|
||||
import frontierModule from "@web3-onboard/frontier";
|
||||
import tahoModule from "@web3-onboard/taho";
|
||||
import coinbaseModule from "@web3-onboard/coinbase";
|
||||
import gnosisModule from "@web3-onboard/gnosis";
|
||||
// import keystoneModule from "@web3-onboard/keystone";
|
||||
// import keepkeyModule from "@web3-onboard/keepkey";
|
||||
// import dcentModule from "@web3-onboard/dcent";
|
||||
// import ledgerModule from "@web3-onboard/ledger";
|
||||
// import trezorModule from "@web3-onboard/trezor";
|
||||
// import walletConnectModule from "@web3-onboard/walletconnect";
|
||||
// import fortmaticModule from "@web3-onboard/fortmatic";
|
||||
// import portisModule from "@web3-onboard/portis";
|
||||
// import magicModule from "@web3-onboard/magic";
|
||||
|
||||
global.Buffer = Buffer;
|
||||
|
||||
export function generateNonce() {
|
||||
@ -147,3 +165,174 @@ export async function authViaMetaMask(application, provider, method) {
|
||||
showMessage("error", `${i18next.t("login:Failed to obtain MetaMask authorization")}: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
const web3Wallets = {
|
||||
// injected wallets
|
||||
injected: {
|
||||
label: "Injected",
|
||||
wallet: injectedModule(),
|
||||
},
|
||||
// sdk wallets
|
||||
coinbase: {
|
||||
label: "Coinbase",
|
||||
wallet: coinbaseModule(),
|
||||
},
|
||||
trust: {
|
||||
label: "Trust",
|
||||
wallet: trustModule(),
|
||||
},
|
||||
gnosis: {
|
||||
label: "Gnosis",
|
||||
wallet: gnosisModule(),
|
||||
},
|
||||
sequence: {
|
||||
label: "Sequence",
|
||||
wallet: sequenceModule(),
|
||||
},
|
||||
taho: {
|
||||
label: "Taho",
|
||||
wallet: tahoModule(),
|
||||
},
|
||||
frontier: {
|
||||
label: "Frontier",
|
||||
wallet: frontierModule(),
|
||||
},
|
||||
infinityWallet: {
|
||||
label: "Infinity Wallet",
|
||||
wallet: infinityWalletModule(),
|
||||
},
|
||||
// hardware wallets
|
||||
// keystone: {
|
||||
// label: "Keystone",
|
||||
// wallet: keystoneModule(),
|
||||
// },
|
||||
// keepkey: {
|
||||
// label: "KeepKey",
|
||||
// wallet: keepkeyModule(),
|
||||
// },
|
||||
// dcent: {
|
||||
// label: "D'CENT",
|
||||
// wallet: dcentModule(),
|
||||
// },
|
||||
|
||||
// some wallet need custome `apiKey` or `projectId` configure item
|
||||
// const magic = magicModule({
|
||||
// apiKey: "magicApiKey",
|
||||
// });
|
||||
// const fortmatic = fortmaticModule({
|
||||
// apiKey: "fortmaticApiKey",
|
||||
// });
|
||||
// const portis = portisModule({
|
||||
// apiKey: "portisApiKey",
|
||||
// });
|
||||
// const ledger = ledgerModule({
|
||||
// projectId: "ledgerProjectId"
|
||||
// });
|
||||
// const walletConnect = walletConnectModule({
|
||||
// projectId: "walletConnectProjectId",
|
||||
// });
|
||||
};
|
||||
|
||||
export function getWeb3OnboardWalletsOptions() {
|
||||
return Object.entries(web3Wallets).map(([key, value]) => ({
|
||||
label: value.label,
|
||||
value: key,
|
||||
}));
|
||||
}
|
||||
|
||||
function getWeb3OnboardWallets(options) {
|
||||
if (options === null || options === undefined || !Array.isArray(options)) {
|
||||
return [];
|
||||
}
|
||||
return options.map(walletType => {
|
||||
if (walletType && web3Wallets[walletType]?.wallet) {
|
||||
return web3Wallets[walletType]?.wallet;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function initWeb3Onboard(application, provider) {
|
||||
// init wallet
|
||||
// options = ["injected","coinbase",...]
|
||||
const options = JSON.parse(provider.metadata);
|
||||
const wallets = getWeb3OnboardWallets(options);
|
||||
|
||||
// init chain
|
||||
// const InfuraKey = "2fa45cbe531e4e65be4fcbf408e651a8";
|
||||
const chains = [
|
||||
// {
|
||||
// id: "0x1",
|
||||
// token: "ETH",
|
||||
// label: "Ethereum Mainnet",
|
||||
// rpcUrl: `https://mainnet.infura.io/v3/${InfuraKey}`,
|
||||
// },
|
||||
// {
|
||||
// id: "0x5",
|
||||
// token: "ETH",
|
||||
// label: "Goerli",
|
||||
// rpcUrl: `https://goerli.infura.io/v3/${InfuraKey}`,
|
||||
// },
|
||||
{
|
||||
id: "0x13881",
|
||||
token: "MATIC",
|
||||
label: "Polygon - Mumbai",
|
||||
rpcUrl: "https://matic-mumbai.chainstacklabs.com",
|
||||
},
|
||||
{
|
||||
id: "0x38",
|
||||
token: "BNB",
|
||||
label: "Binance",
|
||||
rpcUrl: "https://bsc-dataseed.binance.org/",
|
||||
},
|
||||
{
|
||||
id: "0xA",
|
||||
token: "OETH",
|
||||
label: "Optimism",
|
||||
rpcUrl: "https://mainnet.optimism.io",
|
||||
},
|
||||
{
|
||||
id: "0xA4B1",
|
||||
token: "ARB-ETH",
|
||||
label: "Arbitrum",
|
||||
rpcUrl: "https://rpc.ankr.com/arbitrum",
|
||||
},
|
||||
];
|
||||
|
||||
const appMetadata = {
|
||||
name: "Casdoor",
|
||||
description: "Connect a wallet using Casdoor",
|
||||
recommendedInjectedWallets: [
|
||||
{name: "MetaMask", url: "https://metamask.io"},
|
||||
{name: "Coinbase", url: "https://wallet.coinbase.com/"},
|
||||
],
|
||||
};
|
||||
|
||||
const web3Onboard = Onboard({
|
||||
wallets,
|
||||
chains,
|
||||
appMetadata,
|
||||
});
|
||||
return web3Onboard;
|
||||
}
|
||||
|
||||
export async function authViaWeb3Onboard(application, provider, method) {
|
||||
try {
|
||||
const onboard = initWeb3Onboard(application, provider);
|
||||
const connectedWallets = await onboard.connectWallet();
|
||||
if (connectedWallets.length > 0) {
|
||||
const wallet = connectedWallets[0];
|
||||
const account = wallet.accounts[0];
|
||||
const address = account.address;
|
||||
const token = {
|
||||
address: address, // e.g."0xbd5444d31fe4139ee36bea29e43d4ac67ae276de"
|
||||
walletType: wallet.label, // e.g."MetaMask"
|
||||
createAt: Math.floor(new Date().getTime() / 1000),
|
||||
};
|
||||
setWeb3AuthToken(token);
|
||||
const redirectUri = `${getAuthUrl(application, provider, method)}&web3AuthTokenKey=${getWeb3AuthTokenKey(address)}`;
|
||||
goToLink(redirectUri);
|
||||
}
|
||||
} catch (err) {
|
||||
showMessage("error", `${i18next.t("login:Failed to obtain Web3-Onboard authorization")}: ${err}`);
|
||||
}
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ class OAuthWidget extends React.Component {
|
||||
// should add the unlink user's info, cause the user may not be logged in, but a admin want to unlink the user.
|
||||
user: this.props.user,
|
||||
};
|
||||
if (providerType === "MetaMask") {
|
||||
if (providerType === "MetaMask" || providerType === "Web3Onboard") {
|
||||
delWeb3AuthToken(linkedValue);
|
||||
}
|
||||
AuthBackend.unlink(body)
|
||||
@ -158,7 +158,12 @@ class OAuthWidget extends React.Component {
|
||||
</Col>
|
||||
<Col span={24 - this.props.labelSpan} >
|
||||
<AccountAvatar style={{marginRight: "10px"}} size={30} src={avatarUrl} alt={name} referrerPolicy="no-referrer" />
|
||||
<span style={{width: this.props.labelSpan === 3 ? "300px" : "200px", display: (Setting.isMobile()) ? "inline" : "inline-block"}}>
|
||||
<span style={{
|
||||
width: this.props.labelSpan === 3 ? "300px" : "200px",
|
||||
display: (Setting.isMobile()) ? "inline" : "inline-block",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
}} title={name}>
|
||||
{
|
||||
linkedValue === "" ? (
|
||||
`(${i18next.t("general:empty")})`
|
||||
|
2429
web/yarn.lock
2429
web/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user