Skip to content

Commit

Permalink
Merge pull request #63 from walt-id/feat/Algorand
Browse files Browse the repository at this point in the history
Feat/algorand
  • Loading branch information
SuperBatata authored Aug 11, 2023
2 parents b7c8244 + b2dc991 commit 81e5216
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 6 deletions.
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ dependencies {
testImplementation("io.kotest:kotest-assertions-json:5.5.5")

// NftKit
implementation("id.walt:waltid-nftkit:1.2305230002.0")
implementation("id.walt:waltid-nftkit:1.2308101426.0")

// HTTP / Client: ktor
implementation("io.ktor:ktor-client-core:2.2.4")
Expand Down
6 changes: 6 additions & 0 deletions config/idp-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@
"factorySmartContractAddress": "",
"smartContractAddress": "0xa9ccb9756a0ee7eb",
"collectionPath": "/public/exampleNFTCollection"
},
"ALGORAND": {
"chain": "TESTNET",
"factorySmartContractAddress": "",
"smartContractAddress": "266553681",
"collectionPath": ""
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/id/walt/idp/config/ClaimConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class NFTClaimMapping(
}
ChainEcosystem.POLKADOT -> verificationResult.nftresponseVerificationResult.metadata?.uniqueNftMetadata?.attributes?.let { a -> a.firstOrNull { a -> a.name == mappingDefinition.trait }?.value}
ChainEcosystem.FLOW -> verificationResult.nftresponseVerificationResult.metadata?.flowNftMetadata?.traits?.traits?.firstOrNull { a -> a.name == mappingDefinition.trait }?.value

ChainEcosystem.ALGORAND -> verificationResult.nftresponseVerificationResult.metadata?.algorandNftMetadata

}?: throw BadRequestResponse("Requested nft metadata trait not found in verification response")

Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/id/walt/idp/nfts/NFTClaims.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ data class NftTokenConstraint(
)

enum class ChainEcosystem {
EVM, TEZOS, NEAR , POLKADOT , FLOW
EVM, TEZOS, NEAR , POLKADOT , FLOW , ALGORAND
}

data class NftTokenClaim(
Expand Down
6 changes: 5 additions & 1 deletion src/main/kotlin/id/walt/idp/nfts/NFTController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,12 @@ object NFTController {
address = siwfManager.getAddress(message)
siwfManager.verifySignature(session!!, message, signature)

}


ChainEcosystem.ALGORAND -> {
address = SiwaManager.getAddress(message)
val publicKey = SiwaManager.getPublicKey(message)
SiwaManager.verifySignature(session!!, message, publicKey,signature)
}

}
Expand Down
10 changes: 9 additions & 1 deletion src/main/kotlin/id/walt/idp/nfts/NFTManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ object NFTManager {
ChainEcosystem.FLOW -> VerificationService.verifyNftOwnershipInCollectionFlow(tokenConstraint.chain!!,
tokenConstraint.smartContractAddress!!,account ,tokenConstraint.collectionPath!!)

ChainEcosystem.ALGORAND -> VerificationService.NFTsAlgorandOwnershipVerification(AlgorandChain.valueOf(
tokenConstraint.chain!!.toString()
),account,tokenConstraint.smartContractAddress!!)
}
} else {
println("data nft verification")
Expand Down Expand Up @@ -125,7 +128,12 @@ object NFTManager {
flowNftMetadata = if(ecosystem == ChainEcosystem.FLOW)
FlowNftService.getAllNFTs(account , FlowChain.valueOf(tokenConstraint.chain!!.toString()) ).get(0)

else null
else null,

algorandNftMetadata = if (ecosystem == ChainEcosystem.ALGORAND)
AlgorandNftService.getAccountAssets(account,AlgorandChain.valueOf(tokenConstraint.chain!!.toString())).get(0).Metadata
else null

)
}

Expand Down
70 changes: 70 additions & 0 deletions src/main/kotlin/id/walt/idp/siwe/siwaManager.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package id.walt.idp.siwe

import id.walt.idp.config.IDPConfig
import id.walt.idp.oidc.OIDCSession
import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.engine.cio.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.plugins.logging.*
import io.ktor.client.request.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.json.Json
import java.net.URLEncoder
import java.nio.charset.StandardCharsets

object SiwaManager {
val client = HttpClient(CIO.create{requestTimeout = 0}) {
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
})
}
install(Logging) {
logger = Logger.SIMPLE
level = LogLevel.ALL
}
expectSuccess = false
}


fun verifySignature(session: OIDCSession, message: String, publicKey: String, signature: String): Boolean{

val nonce= getNonce(message)
if (session.siweSession?.nonce != nonce) {
return false;
}
if (SiweManager.nonceBlacklists.contains(nonce)) {
return false
}
SiweManager.nonceBlacklists.add(nonce)


return runBlocking {
val result = client.get("${IDPConfig.config.jsProjectExternalUrl}/algorand/signature/verification?publicKey=${publicKey}&signature=${URLEncoder.encode(signature, StandardCharsets.UTF_8)}&message=${URLEncoder.encode(message, StandardCharsets.UTF_8)}") {
}.body<Boolean>()
return@runBlocking result
}
}



fun getAddress(message:String): String{
val regex = Regex("Public Key: ([A-Z0-9]+)\\s*\\.\\s*Date:")
val matchResult = regex.find(message)
val publicKey = matchResult?.groupValues?.get(1)
return publicKey!!
}

fun getNonce(message: String): String{
val nonce= message.split(".").last().split(":").last().trim()
return nonce
}
fun getPublicKey(message: String): String {
val regex = Regex("Public Key: ([A-Z0-9]+)\\s*\\.\\s*Date:")
val matchResult = regex.find(message)
val publicKey = matchResult?.groupValues?.get(1)
return publicKey!!
}
}
3 changes: 2 additions & 1 deletion web/waltid-idpkit-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"@polkadot/api": "^10.8.1",
"@polkadot/extension-dapp": "^0.46.4",
"@polkadot/util": "^12.2.2",
"@randlabs/myalgo-connect": "^1.4.2",
"@taquito/beacon-wallet": "^15.0.0",
"@taquito/taquito": "^15.0.0",
"@vue/cli-plugin-babel": "^5.0.8",
Expand All @@ -56,6 +57,6 @@
"webpack": "^4.46.0"
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object" : "^7.14.5"
"@babel/plugin-proposal-private-property-in-object": "^7.14.5"
}
}
47 changes: 47 additions & 0 deletions web/waltid-idpkit-ui/pages/connect-wallet.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
Connect wallet(Flow)
</button>
</div>
<div class="text-center">
<br />
<button class="btn btn-success" @click="AlgorandWallet">
Connect wallet(Algorand)
</button>
</div>
</div>
</div>
</template>
Expand All @@ -47,6 +53,7 @@ import { setupWalletSelector } from "@near-wallet-selector/core";
import { setupModal } from "@near-wallet-selector/modal-ui";
import { setupWelldoneWallet } from "@near-wallet-selector/welldone-wallet";
import MyAlgoConnect from "@randlabs/myalgo-connect";
import { setupDefaultWallets } from "@near-wallet-selector/default-wallets";
import {
Expand Down Expand Up @@ -348,6 +355,46 @@ Nonce: ${nonce}`;
},
async AlgorandWallet(){
const redirect_uri = this.$route.query["redirect_uri"];
const session_id = this.$route.query["session"];
const nonce = this.$route.query["nonce"];
const origin = window.location.origin;
const domain = window.location.host;
const ISO8601formatedTimestamp = new Date().toISOString();
const description = "Sign in with Flow to the app.";
const settings = {
shouldSelectOneAccount: true,
};
const myAlgoWallet = new MyAlgoConnect();
console.log("logging in")
// try {
const accounts = await myAlgoWallet.connect(settings);
const account = accounts[0]
const message = `${domain} wants you to sign in with your Algorand account:${account.name} . Public Key: ${account.address} .Date: ${ISO8601formatedTimestamp}. ${description} URI: ${origin}. Version: 1. Nonce: ${nonce}`;
const textEncoder = new TextEncoder();
const encodedMessage = textEncoder.encode(message);
const data = new Uint8Array([...encodedMessage]);
const signature = await myAlgoWallet.signBytes(data, account.address);
const urlSignature = encodeURIComponent(JSON.stringify(signature))
const urlMessage = encodeURIComponent(message);
let url = `${redirect_uri}?session=${session_id}&ecosystem=Algorand&message=${urlMessage}&signature=${signature}`;
window.location = url;
}
},
};
</script>
Expand Down

0 comments on commit 81e5216

Please sign in to comment.