package manager import ( "context" "encoding/base64" "encoding/json" "fmt" "strings" "chainweaver.org.cn/chainweaver/did/core" "chainweaver.org.cn/chainweaver/did/core/crypto" "chainweaver.org.cn/chainweaver/did/did-kms/kms" "chainweaver.org.cn/chainweaver/did/did-mgr-common-service/errorcode" "chainweaver.org.cn/chainweaver/did/did-mgr-common-service/internal/config" "chainweaver.org.cn/chainweaver/did/did-mgr-common-service/internal/db" "chainweaver.org.cn/chainweaver/did/did-mgr-common-service/internal/logic/authority" "chainweaver.org.cn/chainweaver/did/did-mgr-common-service/internal/middleware" "chainweaver.org.cn/chainweaver/did/did-mgr-common-service/internal/svc" "chainweaver.org.cn/chainweaver/did/did-mgr-common-service/internal/types" "chainweaver.org.cn/chainweaver/did/did-mgr-common-service/internal/utils" "chainweaver.org.cn/chainweaver/servicecommon/res/code" "google.golang.org/grpc/metadata" "github.com/zeromicro/go-zero/core/logx" ) const OperatorCenterDID = "did:cndid:cndid" type AddDidLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } func NewAddDidLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddDidLogic { return &AddDidLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } func (l *AddDidLogic) AddDid(req *types.KeyPairReq) (resp *types.CommonResp, err error) { resp = &types.CommonResp{ Code: types.SucceedCode, Msg: types.SucceedMsg, } priKey, err := base64.StdEncoding.DecodeString(req.PrivateKey) if err != nil { errorcode.ParseErrorParsePrivateKeyFromPEM.BuildResult(resp, err) logx.Errorf("private key [%s] Parse err[%s]", req.PrivateKey, err.Error()) return resp, nil } // 检查秘钥对是否有效,并计算address privateKey, err := crypto.ParsePrivateKeyFromPEM(priKey) if err != nil { errorcode.ParseErrorParsePrivateKeyFromPEM.BuildResult(resp, err) logx.Errorf("private key [%s] Parse err[%s]", req.PrivateKey, err.Error()) return resp, nil } pkPem, _ := privateKey.PublicKey().String() address, _ := utils.ComputeEVMAddressFromPKPEM([]string{pkPem}) // check did 是否已经绑定 did, err := db.FindDidInfo() if err != nil && err.Error() != "record not found" { errorcode.MysqlErrorQuery.BuildResult(resp, err) logx.Errorf("did [%s] has exist", address[0]) return resp, nil } if did != nil { errorcode.DidAlreadyExistError.BuildResult(resp) logx.Errorf("did has exist,dup add did") return resp, nil } //去运营端根据did address查询did,以及实名vc信息 targetUrl := config.ConfigIns.Service.Did + utils.DIdGetDocumentByAddressUrl proxy := config.ConfigIns.Service.DidProxy docReq := &utils.DocumentGetByAddressRequest{Address: address[0]} document, err := utils.GetDocument(targetUrl, proxy, docReq) if err != nil { if strings.Contains(err.Error(), "record not found") { errorcode.DidIsNotExistError.BuildResult(resp) logx.Errorf("get [%s] vc by address of remote did service, err[%s]", address[0], err.Error()) return resp, nil } errorcode.DocumentRequestError.BuildResult(resp, err) logx.Errorf("get [%s] document by address of remote did service, err[%s]", address[0], err.Error()) return resp, nil } // 运营平台 did 必须是固定的 if config.ConfigIns.IsOperatorCenter == 1 { if document.Id != OperatorCenterDID { err = fmt.Errorf("add operationCenter did failed,did id expected [%s],but get [%s]", OperatorCenterDID, document.Id) errorcode.OperationCenterErrorDid.BuildResult(resp, err) logx.Errorf(err.Error()) return resp, nil } } //去远端拉取vc信息,并将vc信息存储 proxy = config.ConfigIns.Service.DidProxy targetUrl = config.ConfigIns.Service.Did + utils.VcListUser vcByte, err := utils.GetRealNameVc(targetUrl, proxy, document.Id) if err != nil { errorcode.DocumentRequestError.BuildResult(resp, err) logx.Errorf("get [%s] vc by address of remote did service, err[%s]", address[0], err.Error()) return resp, nil } vc := &core.VerifiableCredential{} enterAuthority := &authority.EnterpriseAuthority{} err = json.Unmarshal(vcByte.Vc, vc) if err != nil { err = fmt.Errorf("unmarshal vc failed, err[%s]", err.Error()) errorcode.MarshalOrUnMarshalError.BuildResult(resp, err) l.Errorf(err.Error()) return resp, nil } err = json.Unmarshal(vc.CredentialSubject, enterAuthority) if err != nil { err = fmt.Errorf("unmarshal enterAuthority failed, err[%s]", err.Error()) errorcode.MarshalOrUnMarshalError.BuildResult(resp, err) l.Errorf(err.Error()) return resp, nil } token := l.ctx.Value("claims").(*middleware.TokenUser) // 2. 记录到数据库 opFromDate := utils.ParseAndFormatTime(enterAuthority.Opfrom) opToDate := utils.ParseAndFormatTime(enterAuthority.Opto) enterC := &db.EnterpriseCertInfo{ EnterpriseID: token.EnterpriseId, EnterpriseName: enterAuthority.Entname, Uniscid: enterAuthority.Uniscid, LegalName: enterAuthority.LegalName, Dom: enterAuthority.Dom, LegalIDCard: "", LegalPhone: "", EnterCardType: 1, // 企业证件类型 Opscope: enterAuthority.Opscope, // 经营范围 Opfrom: opFromDate, Opto: opToDate, Licencesn: enterAuthority.Licencesn, // 电子营业执照序列号 CardType: 1, VcPlaintext: string(vcByte.Vc), } err = db.CreateTable(enterC) if err != nil { errorcode.MysqlErrorInsertInfo.BuildResult(resp, err) l.Errorf(err.Error()) return resp, nil } enterInfo, err := db.FindEnterpriseInfoById(token.EnterpriseId) if err != nil { errorcode.MysqlErrorQuery.BuildResult(resp, err) l.Errorf(err.Error()) return resp, nil } enterInfo.CertificationState = 1 err = db.UpdateEnterpriseInfo(enterInfo) if err != nil { errorcode.MysqlErrorInsertInfo.BuildResult(resp, err) l.Errorf(err.Error()) return resp, nil } req.PrivateKey = string(priKey) //保存私钥到kms resKey, err := l.AddKeyPair(req) if err != nil { errorcode.KmsAddDataError.BuildResult(resp, err) l.Logger.Info("kms add key failed,err[%s]", err.Error()) return resp, nil } //2.local save err = db.CreateTable(&db.KeyInfo{ Address: resKey.Data, AdminName: token.UserName, State: 1, Enable: 1, Remark: req.Mnemonic, }) if err != nil { errorcode.MysqlErrorInsertInfo.BuildResult(resp, err) l.Logger.Info("create key info failed,err[%s]", err.Error()) return resp, nil } docByte, err := json.Marshal(document) if err != nil { errorcode.MarshalOrUnMarshalError.BuildResult(resp, err) l.Errorf("marshal document failed,err[%s]", err.Error()) return resp, nil } // 保存 did信息到kms _, err = AddDidInfo(l.svcCtx.KmsClient, docByte, document.Id) if err != nil { errorcode.KmsAddDataError.BuildResult(resp, err) l.Logger.Info("kms add did failed,err[%s]", err.Error()) return resp, nil } // 3. 将did信息返回给客户端 didInfo := &db.DidInfo{ Did: document.Id, DocumentPlaintext: string(docByte), EnterpriseID: token.EnterpriseId, } err = db.CreateTable(didInfo) if err != nil { errorcode.MysqlErrorInsertInfo.BuildResult(resp, err) l.Errorf("create did info failed,err[%s]", err.Error()) return resp, nil } return resp, nil } func (l *AddDidLogic) AddKeyPair(req *types.KeyPairReq) (*kms.AddKeyPairResponse, error) { in := &kms.AddKeyPairRequest{ PrivateKey: req.PrivateKey, Mnemonic: strings.Split(req.Mnemonic, " "), } // 在请求头中设置自定义参数 ctx := context.Background() //md := metadata.Pairs("did", "my-value") //ctx = metadata.NewOutgoingContext(ctx, md) res, err := l.svcCtx.KmsClient.AddKeyPair(ctx, in) if err != nil { return nil, err } else if code.CodeOk.NotEqualsInt32(res.Code) { return nil, fmt.Errorf(res.Msg) } return res, err } func AddDidInfo(client kms.Kms, documentPlaintext []byte, did string) (*kms.AddDidResponse, error) { plaintext := base64.StdEncoding.EncodeToString(documentPlaintext) // 在请求头中设置自定义参数 ctx := context.Background() md := metadata.Pairs("did", did) ctx = metadata.NewOutgoingContext(ctx, md) in := &kms.AddDidRequest{ Plaintext: plaintext, } res, err := client.AddDid(ctx, in) if err != nil { return nil, err } else if code.CodeOk.NotEqualsInt32(res.Code) { return nil, fmt.Errorf(res.Msg) } return res, err }