mirror of
https://github.com/onsonr/hway.git
synced 2025-03-10 04:57:08 +00:00
feat: add Sonr Communication Infrastructure
This commit is contained in:
parent
7fef4a8522
commit
951dc860d3
@ -1,3 +1,6 @@
|
||||
|
||||
|
||||
# For goreleaser
|
||||
FROM scratch
|
||||
ENTRYPOINT ["/hway"]
|
||||
COPY hway /
|
||||
|
4
deploy/README.md
Normal file
4
deploy/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
# `matrix`
|
||||
|
||||
Sonr Communication infrastructure which allows for Sonr Blockchain
|
||||
Identities to have a secure and private communication channel.
|
6
deploy/gateway/Dockerfile
Normal file
6
deploy/gateway/Dockerfile
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
# For goreleaser
|
||||
FROM scratch
|
||||
ENTRYPOINT ["/hway"]
|
||||
COPY hway /
|
6
deploy/matrix/Dockerfile
Normal file
6
deploy/matrix/Dockerfile
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
# For goreleaser
|
||||
FROM scratch
|
||||
ENTRYPOINT ["/hway"]
|
||||
COPY hway /
|
5
deploy/matrix/bootstrap.sh
Executable file
5
deploy/matrix/bootstrap.sh
Executable file
@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
|
24
deploy/matrix/devbox.json
Normal file
24
deploy/matrix/devbox.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.13.7/.schema/devbox.schema.json",
|
||||
"packages": [
|
||||
"go@latest",
|
||||
"cargo@latest",
|
||||
"uv@latest",
|
||||
"bun@latest"
|
||||
],
|
||||
"env": {
|
||||
"PATH": "$HOME/.cargo/bin:$HOME/go/bin:$HOME/.local/bin:$HOME/.bun/bin:$PATH",
|
||||
"GITHUB_TOKEN": "$GITHUB_TOKEN",
|
||||
"GOPATH": "$HOME/go",
|
||||
"GOBIN": "$GOPATH/bin",
|
||||
"GHQ_ROOT": "$CLONEDIR"
|
||||
},
|
||||
"shell": {
|
||||
"init_hook": [],
|
||||
"scripts": {
|
||||
"test": [
|
||||
"echo \"Error: no test specified\" && exit 1"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
38
x/register/islands/card_account.templ
Normal file
38
x/register/islands/card_account.templ
Normal file
@ -0,0 +1,38 @@
|
||||
package islands
|
||||
|
||||
templ CardAccount(addr, name, handle, creationBlock string) {
|
||||
<div class="profile-card min-w-[320px]">
|
||||
<div class="text-white max-w-xs my-auto mx-auto bg-gradient-to-r from-cyan-600 to-cyan-300 p-4 py-5 px-5 rounded-xl">
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
<h2>sonr-testnet-1</h2>
|
||||
<p class="text-2xl font-bold">{ handle }</p>
|
||||
</div>
|
||||
<div class="flex items-center opacity-60">
|
||||
<sl-icon style="font-size: 52px;" library="sonr" name="sonr-fill"></sl-icon>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 flex justify-between items-center w-52">
|
||||
<span class="text-lg font-mono">{ shortenAddress(addr) }</span>
|
||||
</div>
|
||||
<div class="flex justify-between mt-5 w-48 ">
|
||||
<div>
|
||||
<h3 class="text-xs">Block Created </h3>
|
||||
<p class="font-bold"><span>#</span>{ creationBlock }</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-xs">Issued to</h3>
|
||||
<p class="font-bold">{ name }</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
// Helper function to shorten address
|
||||
func shortenAddress(address string) string {
|
||||
if len(address) <= 20 {
|
||||
return address
|
||||
}
|
||||
return address[:16] + "..." + address[len(address)-4:]
|
||||
}
|
70
x/register/islands/coin_select.templ
Normal file
70
x/register/islands/coin_select.templ
Normal file
@ -0,0 +1,70 @@
|
||||
package islands
|
||||
|
||||
type Coin struct {
|
||||
Ticker string
|
||||
Name string
|
||||
IsDefault bool
|
||||
}
|
||||
|
||||
var defaultCoins = []Coin{
|
||||
{Ticker: "SNR", Name: "Sonr", IsDefault: true},
|
||||
{Ticker: "BTC", Name: "Bitcoin", IsDefault: true},
|
||||
{Ticker: "ETH", Name: "Ethereum", IsDefault: true},
|
||||
{Ticker: "SOL", Name: "Solana", IsDefault: false},
|
||||
{Ticker: "LTC", Name: "Litecoin", IsDefault: false},
|
||||
{Ticker: "DOGE", Name: "Dogecoin", IsDefault: false},
|
||||
{Ticker: "XRP", Name: "Ripple", IsDefault: false},
|
||||
{Ticker: "OSMO", Name: "Osmosis", IsDefault: false},
|
||||
{Ticker: "ATOM", Name: "Cosmos", IsDefault: false},
|
||||
{Ticker: "STARZ", Name: "Stargaze", IsDefault: false},
|
||||
{Ticker: "AKT", Name: "Akash", IsDefault: false},
|
||||
{Ticker: "EVMOS", Name: "Evmos", IsDefault: false},
|
||||
{Ticker: "FIL", Name: "Filecoin", IsDefault: false},
|
||||
{Ticker: "AXL", Name: "Axelar", IsDefault: false},
|
||||
}
|
||||
|
||||
templ CoinSelect() {
|
||||
<sl-select
|
||||
label="Accounts"
|
||||
name="selected_assets"
|
||||
value="SNR BTC ETH"
|
||||
help-text="Select Blockchains to connect with your Vault"
|
||||
multiple
|
||||
class="custom-tag py-2"
|
||||
>
|
||||
for _, a := range defaultCoins {
|
||||
@CoinOption(a)
|
||||
}
|
||||
</sl-select>
|
||||
<script>
|
||||
const select = document.querySelector('.custom-tag');
|
||||
select.getTag = (option, index) => {
|
||||
// Use the same icon used in the <sl-option>
|
||||
const name = option.querySelector('sl-icon[slot="prefix"]').name;
|
||||
|
||||
// You can return a string, a Lit Template, or an HTMLElement here
|
||||
return `
|
||||
<sl-tag removable>
|
||||
<sl-icon name="${name}" library="crypto" style="padding-inline-end: .5rem;"></sl-icon>
|
||||
${option.getTextLabel()}
|
||||
</sl-tag>
|
||||
`;
|
||||
};
|
||||
</script>
|
||||
}
|
||||
|
||||
templ CoinOption(a Coin) {
|
||||
if a.IsDefault {
|
||||
<sl-option value={ a.Ticker } selected disabled>
|
||||
<sl-icon slot="prefix" name={ a.Ticker } library="crypto"></sl-icon>
|
||||
{ a.Name }
|
||||
</sl-option>
|
||||
<sl-divider></sl-divider>
|
||||
} else {
|
||||
<sl-option value={ a.Ticker }>
|
||||
<sl-icon slot="prefix" name={ a.Ticker } library="crypto"></sl-icon>
|
||||
{ a.Name }
|
||||
</sl-option>
|
||||
<sl-divider></sl-divider>
|
||||
}
|
||||
}
|
25
x/register/islands/human_slider.templ
Normal file
25
x/register/islands/human_slider.templ
Normal file
@ -0,0 +1,25 @@
|
||||
package islands
|
||||
|
||||
import "fmt"
|
||||
|
||||
templ HumanSlider(firstNumber int, lastNumber int) {
|
||||
<div hx-target="this" hx-swap="outerHTML">
|
||||
<sl-range name="is_human" label={ humanLabel(firstNumber, lastNumber) } help-text="Prove you are a human." min="0" max="9" step="1" hx-post="/register/profile/is_human"></sl-range>
|
||||
</div>
|
||||
}
|
||||
|
||||
templ HumanSliderError(firstNumber int, lastNumber int) {
|
||||
<sl-range name="is_human" label={ humanLabel(firstNumber, lastNumber) } help-text="Prove you are a human." min="0" max="9" step="1"></sl-range>
|
||||
<div slot="help-text">
|
||||
<sl-icon name="x-lg" library="sonr"></sl-icon>
|
||||
Invalid Human Sum
|
||||
</div>
|
||||
}
|
||||
|
||||
templ HumanSliderSuccess() {
|
||||
<sl-range name="is_human" label="Success! Welcome Human." help-text="Prove you are a human." min="0" max="9" step="1" value="9" disabled></sl-range>
|
||||
}
|
||||
|
||||
func humanLabel(firstNumber int, lastNumber int) string {
|
||||
return fmt.Sprintf("What is %d + %d?", firstNumber, lastNumber)
|
||||
}
|
45
x/register/islands/input_handle.templ
Normal file
45
x/register/islands/input_handle.templ
Normal file
@ -0,0 +1,45 @@
|
||||
package islands
|
||||
|
||||
type HandleState string
|
||||
|
||||
const (
|
||||
HandleStateInitial HandleState = "inital"
|
||||
HandleStateValid HandleState = "valid"
|
||||
HandleStateInvalid HandleState = "invalid"
|
||||
)
|
||||
|
||||
func (s HandleState) string() string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
templ InputHandle() {
|
||||
<div hx-target="this" hx-swap="outerHTML">
|
||||
<sl-input name="handle" placeholder="digitalgold" type="text" label="Handle" minlength="4" maxlength="12" required hx-post="/register/profile" hx-indicator="#handle-indicator" autofocus>
|
||||
<div slot="prefix">
|
||||
<sl-icon name="at-sign" library="sonr"></sl-icon>
|
||||
</div>
|
||||
</sl-input>
|
||||
</div>
|
||||
<br/>
|
||||
}
|
||||
|
||||
templ InputHandleError(value string, helpText string) {
|
||||
<sl-input name="handle" placeholder="digitalgold" type="text" label="Handle" minlength="4" maxlength="12" required class="border-red-500" value={ value } help-text={ helpText }>
|
||||
<div slot="prefix">
|
||||
<sl-icon name="at-sign" library="sonr"></sl-icon>
|
||||
</div>
|
||||
<div slot="suffix" style="color: #B54549;">
|
||||
<sl-icon name="x"></sl-icon>
|
||||
</div>
|
||||
</sl-input>
|
||||
<br/>
|
||||
}
|
||||
|
||||
templ InputHandleSuccess(value string) {
|
||||
<sl-input name="handle" placeholder="digitalgold" type="text" label="Handle" minlength="4" maxlength="12" required class="border-green-500" value={ value } disabled>
|
||||
<div slot="prefix" style="color: #46A758;">
|
||||
<sl-icon name="at-sign" library="sonr"></sl-icon>
|
||||
</div>
|
||||
</sl-input>
|
||||
<br/>
|
||||
}
|
97
x/register/islands/input_passkey.templ
Normal file
97
x/register/islands/input_passkey.templ
Normal file
@ -0,0 +1,97 @@
|
||||
package islands
|
||||
|
||||
templ InputPasskey(addr string, userHandle string, challenge string) {
|
||||
<sl-button style="width: 100%;" onclick={ navigatorCredentialsCreate(addr, userHandle, challenge) }>
|
||||
<sl-icon slot="prefix" name="passkey" library="sonr" style="font-size: 24px;" class="text-neutral-500"></sl-icon>
|
||||
Register Passkey
|
||||
</sl-button>
|
||||
}
|
||||
|
||||
script navigatorCredentialsCreate(userId string, userHandle string, challenge string) {
|
||||
const publicKey = {
|
||||
challenge: Uint8Array.from(challenge, (c) => c.charCodeAt(0)),
|
||||
rp: {
|
||||
name: "Sonr.ID",
|
||||
},
|
||||
user: {
|
||||
// Assuming that userId is ASCII-only
|
||||
id: Uint8Array.from(userId, (c) => c.charCodeAt(0)),
|
||||
name: userId,
|
||||
displayName: userHandle,
|
||||
},
|
||||
pubKeyCredParams: [
|
||||
{
|
||||
type: "public-key",
|
||||
alg: -7, // "ES256"
|
||||
},
|
||||
{
|
||||
type: "public-key",
|
||||
alg: -257, // "RS256"
|
||||
},
|
||||
],
|
||||
authenticatorSelection: {
|
||||
userVerification: "required",
|
||||
residentKey: "required",
|
||||
authenticatorAttachment: "platform",
|
||||
},
|
||||
timeout: 60000, // 1 minute
|
||||
extensions: {
|
||||
payment: {
|
||||
isPayment: true,
|
||||
},
|
||||
largeBlob: {
|
||||
supported: "preferred",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Helper function to convert ArrayBuffer to Base64URL string
|
||||
function arrayBufferToBase64URL(buffer) {
|
||||
const bytes = new Uint8Array(buffer);
|
||||
let str = '';
|
||||
bytes.forEach(byte => { str += String.fromCharCode(byte) });
|
||||
return btoa(str)
|
||||
.replace(/\+/g, '-')
|
||||
.replace(/\//g, '_')
|
||||
.replace(/=/g, '');
|
||||
}
|
||||
|
||||
navigator.credentials
|
||||
.create({ publicKey })
|
||||
.then((newCredentialInfo) => {
|
||||
if (!(newCredentialInfo instanceof PublicKeyCredential)) {
|
||||
throw new Error('Received credential is not a PublicKeyCredential');
|
||||
}
|
||||
|
||||
const response = newCredentialInfo.response;
|
||||
if (!(response instanceof AuthenticatorAttestationResponse)) {
|
||||
throw new Error('Response is not an AuthenticatorAttestationResponse');
|
||||
}
|
||||
|
||||
// Convert the credential data to a cross-platform compatible format
|
||||
const credentialJSON = {
|
||||
id: newCredentialInfo.id,
|
||||
rawId: arrayBufferToBase64URL(newCredentialInfo.rawId),
|
||||
type: newCredentialInfo.type,
|
||||
authenticatorAttachment: newCredentialInfo.authenticatorAttachment || null,
|
||||
transports: Array.isArray(response.getTransports) ? response.getTransports() : [],
|
||||
clientExtensionResults: newCredentialInfo.getClientExtensionResults(),
|
||||
response: {
|
||||
attestationObject: arrayBufferToBase64URL(response.attestationObject),
|
||||
clientDataJSON: arrayBufferToBase64URL(response.clientDataJSON)
|
||||
}
|
||||
};
|
||||
|
||||
// Set the form value with the stringified credential data
|
||||
const credential = document.getElementById('credential-data');
|
||||
credential.value = JSON.stringify(credentialJSON);
|
||||
|
||||
// Submit the form
|
||||
const form = document.getElementById('passkey-form');
|
||||
form.submit();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Passkey creation failed:', err);
|
||||
alert(`Failed to create passkey: ${err.message || 'Unknown error'}`);
|
||||
});
|
||||
}
|
@ -1 +0,0 @@
|
||||
package handlers
|
@ -1 +0,0 @@
|
||||
package handlers
|
Loading…
x
Reference in New Issue
Block a user