You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

127 lines
3.9 KiB

/*
* Copyright 2024. Huawei Technologies Co., Ltd. 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 harmonyos
import (
"crypto/ecdsa"
"crypto/sha256"
"crypto/x509"
"encoding/hex"
"encoding/json"
"encoding/pem"
"errors"
"github.com/cristalhq/jwt/v3"
"io/ioutil"
"time"
)
type JWTGenerator struct {
}
type IAPJWTClaims struct {
// Iss Key issuer ID.
Iss string `json:"iss"`
// Aud Expected receiver of the JWT. The value is fixed at iap-v1.
Aud string `json:"aud"`
// Iat Time when the JWT is issued. The value is a UTC timestamp, in seconds.
Iat int64 `json:"iat"`
// Exp Time when the JWT expires. The value is a UTC timestamp, in seconds. exp-iat indicates the validity period of the JWT, which cannot exceed one hour.
Exp int64 `json:"exp"`
// Aid App ID.
Aid string `json:"aid"`
// Digest Hash value of the request body (JSON character string), which is used to verify the integrity of the body. The algorithm is SHA-256.
Digest string `json:"digest"`
}
const (
// JWT_PRI_KEY_PATH Private key file path.
JWT_PRI_KEY_PATH = "manifest/config/IAPKey.p8" // TODO: Need to replace it with the actual value.
// ACTIVE_TIME JWT validity period, which is a UTC timestamp in seconds. The validity period cannot exceed 1 hour.
ACTIVE_TIME_SECOND = 3600 // TODO: Need to replace it with the actual value.
KID = "f35b90cf-48be-4bb9-bb66-f7e814d5521c" // TODO: Need to replace it with the actual value.
ISSUER_ID = "002124f1-f9a9-468e-92ea-26561ea9c605" // TODO: Need to replace it with the actual business logic.
APP_ID = "6917589392953468039" // TODO: Need to replace it with the actual business logic.
)
func (jwtGenerator *JWTGenerator) GenJWT(bodyMap map[string]interface{}) (string, error) {
privateKeyPEM, err := ioutil.ReadFile(JWT_PRI_KEY_PATH)
if err != nil {
// TODO: Need to replace it with the actual business logic.
return "", err
}
block, _ := pem.Decode(privateKeyPEM)
if block == nil {
// TODO: Need to replace it with the actual business logic.
return "", errors.New("the key content is empty")
}
privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
// TODO: Need to replace it with the actual business logic.
return "", err
}
ecdsaPrivateKey, ok := privateKey.(*ecdsa.PrivateKey)
if !ok {
// TODO: Need to replace it with the actual business logic.
return "", errors.New("failed to convert private key to *ecdsa.PrivateKey")
}
signer, err := jwt.NewSignerES(jwt.ES256, ecdsaPrivateKey)
if err != nil {
// TODO: Need to replace it with the actual business logic.
return "", err
}
payloadJson, err := json.Marshal(bodyMap)
if err != nil {
// TODO: Need to replace it with the actual business logic.
return "", err
}
hash := sha256.New()
hash.Write(payloadJson)
sha256Sum := hash.Sum(nil)
sha256Hex := hex.EncodeToString(sha256Sum)
builder := jwt.NewBuilder(signer, jwt.WithKeyID(KID)) // TODO: Need to replace it with the actual business logic.
signTime := time.Now().UTC().Unix()
claims := IAPJWTClaims{
Iss: ISSUER_ID, // TODO: Need to replace it with the actual business logic.
Aud: "iap-v1",
Iat: signTime,
Exp: signTime + ACTIVE_TIME_SECOND,
Aid: APP_ID, // TODO: Need to replace it with the actual business logic.
Digest: sha256Hex,
}
iapJwt, err := builder.Build(claims)
if err != nil {
// TODO: Need replace it with your business logic.
return "", err
}
return iapJwt.String(), nil
}