Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

321 update thyra to match the new dns keys formatting #365

Merged
6 changes: 2 additions & 4 deletions int/api/html/front/website.js
Original file line number Diff line number Diff line change
Expand Up @@ -379,12 +379,10 @@ function deployWebsiteAndUpload() {
// Full deployment process
function uploadWebsite(file, count) {
const bodyFormData = new FormData();

const address = deployers[count].address;
bodyFormData.append("zipfile", file);
bodyFormData.append("address", address);
bodyFormData.append("nickname", getDefaultWallet());

uploadProcess(file, deployers[count].name, false, bodyFormData, (bodyFormData) =>
postUpload(bodyFormData)
);
Expand Down Expand Up @@ -447,7 +445,7 @@ function step1(dnsName, totalChunk) {
// Step 2, wait for DNS setting
function step2(dnsName, contractAddress, totalChunk) {
eventManager.subscribe(
`Record name ${dnsName} added to DNS for owner ${getWallet(getDefaultWallet()).address} at address ${contractAddress}`,
`Website name ${dnsName} added to DNS at address ${contractAddress}`,
getWallet(getDefaultWallet()).address,
(_) => {
step3(contractAddress, totalChunk);
Expand All @@ -467,7 +465,7 @@ function step3(contractAddress, totalChunk) {

for (let i = 0; i < totalChunk; i++) {
eventManager.subscribe(
`Website chunk deployed to ${contractAddress} on key massa_web_${i}`,
`Website chunk deployed to ${contractAddress} on key ${i}`,
getWallet(getDefaultWallet()).address,
(_) => {
actualChunk++;
Expand Down
67 changes: 21 additions & 46 deletions int/api/websites/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package websites
import (
"fmt"
"sort"
"strings"

"github.com/go-openapi/runtime/middleware"
"github.com/massalabs/thyra/api/swagger/server/models"
Expand All @@ -12,31 +11,20 @@ import (
"github.com/massalabs/thyra/pkg/node"
"github.com/massalabs/thyra/pkg/node/ledger"
"github.com/massalabs/thyra/pkg/onchain/dns"
"github.com/massalabs/thyra/pkg/wallet"
)

const (
dateFormat = "2006-01-02"
recordKey = "record"
metaKey = "META"
ownedPrefix = "owned"
secondsToMilliCoeff = 1000
)

//nolint:nolintlint,ireturn
func RegistryHandler(params operations.AllDomainsGetterParams) middleware.Responder {
client := node.NewDefaultClient()

addressesResult, err := ledger.Addresses(client, []string{dns.DNSRawAddress})
if err != nil {
return operations.NewMyDomainsGetterInternalServerError().
WithPayload(
&models.Error{
Code: errorCodeGetRegistry,
Message: err.Error(),
})
}

results, err := Registry(client, addressesResult[0].CandidateDatastoreKeys)
results, err := Registry(client)
if err != nil {
return operations.NewMyDomainsGetterInternalServerError().
WithPayload(
Expand All @@ -55,50 +43,37 @@ smart contract Thyra is connected to. Once this data has been fetched from the D
the various website storer contracts, the function builds an array of Registry objects
and returns it to the frontend for display on the Registry page.
*/
func Registry(client *node.Client, candidateDatastoreKeys [][]byte) ([]*models.Registry, error) {
// array of strings of website names : (recordflappy).
recordKeysStrings, err := ledger.KeysFiltered(client, dns.DNSRawAddress, recordKey)
func Registry(client *node.Client) ([]*models.Registry, error) {
websiteNames, err := ledger.FilterSCKeysByPrefix(client, dns.DNSRawAddress, ownedPrefix, false)
if err != nil {
return nil, fmt.Errorf("filtering keys with '%+v' failed : %w", recordKey, err)
return nil, fmt.Errorf("fetching all keys without '%s' prefix at '%s': %w", ownedPrefix, dns.DNSRawAddress, err)
}
// convert array of strings to array of [array of bytes]
recordKeysBytes := make([][]byte, len(recordKeysStrings))
for i, v := range recordKeysStrings {
recordKeysBytes[i] = convert.StringToBytes(v)
}
// retrieve the records owners values : addresses who own the websites.
recordResult, err := node.ContractDatastoreEntries(client, dns.DNSRawAddress, recordKeysBytes)

dnsValues, err := node.ContractDatastoreEntries(client, dns.DNSRawAddress, websiteNames)
if err != nil {
return nil, fmt.Errorf("searching Owners of records (addresses) failed : %w", err)
return nil, fmt.Errorf("reading keys '%s' at '%s': %w", websiteNames, dns.DNSRawAddress, err)
}

var websiteStorers []node.DatastoreEntriesKeysAsString
// in website name key, value are stored in this order -> website Address, website Owner Address
indexOfWebsiteAddress := 0

for _, record := range recordResult {
if wallet.CheckAddress(convert.BytesToString(record.CandidateValue)) {
websiteStorerKey := node.DatastoreEntriesKeysAsString{
Address: convert.BytesToString(record.CandidateValue),
Key: convert.StringToBytes(metaKey + string(record.CandidateValue)),
}
registry := make([]*models.Registry, len(dnsValues))

websiteStorers = append(websiteStorers, websiteStorerKey)
}
}
for index := 0; index < len(dnsValues); index++ {
websiteStorerAddress := convert.ByteToStringArray(dnsValues[index].CandidateValue)[indexOfWebsiteAddress]

websitesMetadata, err := node.DatastoreEntries(client, websiteStorers)
if err != nil {
return nil, fmt.Errorf("metadata reaching on dnsContractStorers failed : %w", err)
}

registry := make([]*models.Registry, len(websitesMetadata))
websiteMetadata, err := node.DatastoreEntry(client, websiteStorerAddress, convert.StringToBytes(metaKey))
if err != nil {
return nil, fmt.Errorf("reading key '%s' at '%s': %w", metaKey, websiteStorerAddress, err)
}

for index := 0; index < len(websitesMetadata); index++ {
registry[index] = &models.Registry{
Name: strings.Split(recordKeysStrings[index], recordKey)[1], // name of website : flappy.
Address: websiteStorers[index].Address, // owner of Website Address.
Metadata: websitesMetadata[index].CandidateValue, // website metadata.
Name: convert.BytesToString(websiteNames[index]), // name of website : flappy.
Address: websiteStorerAddress, // website Address
Metadata: websiteMetadata.CandidateValue, // website metadata.
}
}

// sort website names with alphanumeric order.
sort.Slice(registry, func(i, j int) bool {
return registry[i].Name < registry[j].Name
Expand Down
165 changes: 53 additions & 112 deletions int/api/websites/webcreator.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,43 +41,8 @@ func listFileName(zipReader *zip.Reader) []string {

//nolint:nolintlint,ireturn,funlen
func prepareForWebsiteHandler(params operations.WebsiteCreatorPrepareParams, app *fyne.App) middleware.Responder {
wallet, err := wallet.Load(params.Nickname)
if err != nil {
return createInternalServerError(errorCodeGetWallet, err.Error())
}

clearPassword, err := gui.AskPassword(wallet.Nickname, app)
if err != nil {
return createInternalServerError(ErrorCodeWalletCanceledAction, err.Error())
}

if len(clearPassword) == 0 {
return createInternalServerError(ErrorCodeWalletPasswordEmptyWebCreator, ErrorCodeWalletPasswordEmptyWebCreator)
}

err = wallet.Unprotect(clearPassword, 0)

if err != nil {
return createInternalServerError(errorCodeWalletWrongPassword, err.Error())
}

archive, err := io.ReadAll(params.Zipfile)
if err != nil {
return createInternalServerError(errorCodeWebCreatorReadArchive, err.Error())
}

maxArchiveSize := GetMaxArchiveSize()

if len(archive) > maxArchiveSize {
return createInternalServerError(errorCodeWebCreatorArchiveSize, errorCodeWebCreatorArchiveSize)
}

zipReader, _ := zip.NewReader(bytes.NewReader(archive), int64(len(archive)))
FilesOfArchive := listFileName(zipReader)

if slices.Index(FilesOfArchive, "index.html") == -1 {
return createInternalServerError(errorCodeWebCreatorHTMLNotInSource, errorCodeWebCreatorHTMLNotInSource)
}
wallet, _ := loadAndUnprotectWallet(params.Nickname, app)
archive, _ := readAndCheckArchive(params.Zipfile, app)

address, err := website.PrepareForUpload(params.URL, wallet)
if err != nil {
Expand Down Expand Up @@ -131,57 +96,17 @@ func CreateUploadWebsiteHandler(app *fyne.App) func(params operations.WebsiteCre

//nolint:nolintlint,ireturn
func uploadWebsiteHandler(params operations.WebsiteCreatorUploadParams, app *fyne.App) middleware.Responder {
wallet, err := wallet.Load(params.Nickname)
if err != nil {
return operations.NewWebsiteCreatorUploadInternalServerError().
WithPayload(
&models.Error{
Code: errorCodeGetWallet,
Message: err.Error(),
})
}

clearPassword, err := gui.AskPassword(wallet.Nickname, app)
if err != nil {
return operations.NewWebsiteCreatorUploadInternalServerError().
WithPayload(
&models.Error{
Code: ErrorCodeWalletCanceledAction,
Message: ErrorCodeWalletCanceledAction,
})
}

err = wallet.Unprotect(clearPassword, 0)
if err != nil {
return operations.NewWebsiteCreatorUploadInternalServerError().
WithPayload(
&models.Error{
Code: errorCodeWalletWrongPassword,
Message: err.Error(),
})
}
wallet, _ := loadAndUnprotectWallet(params.Nickname, app)
archive, _ := readAndCheckArchive(params.Zipfile, app)

archive, err := io.ReadAll(params.Zipfile)
if err != nil {
return operations.NewWebsiteCreatorUploadInternalServerError().
WithPayload(&models.Error{
Code: errorCodeWebCreatorReadArchive,
Message: err.Error(),
})
}

if !checkContentType(archive, "application/zip") {
return createInternalServerError(errorCodeWebCreatorFileType, errorCodeWebCreatorFileType)
}

_, err = website.Upload(params.Address, archive, *wallet)
_, err := website.Upload(params.Address, archive, *wallet)
if err != nil {
return createInternalServerError(errorCodeWebCreatorUpload, err.Error())
}

return operations.NewWebsiteCreatorUploadOK().
WithPayload(&models.Websites{
Name: "Name",
Name: "",
Address: params.Address,
BrokenChunks: nil,
})
Expand All @@ -202,53 +127,69 @@ func CreateUploadMissingChunksHandler(app *fyne.App) func(params operations.Webs

//nolint:nolintlint,ireturn,lll
func websiteUploadMissingChunksHandler(params operations.WebsiteUploadMissingChunksParams, app *fyne.App) middleware.Responder {
wallet, err := wallet.Load(params.Nickname)
wallet, _ := loadAndUnprotectWallet(params.Nickname, app)
archive, _ := readAndCheckArchive(params.Zipfile, app)

_, err := website.UploadMissedChunks(params.Address, archive, wallet, params.MissedChunks)
if err != nil {
return createInternalServerError(errorCodeWebCreatorUpload, err.Error())
}

return operations.NewWebsiteUploadMissingChunksOK().
WithPayload(&models.Websites{
Name: "",
Address: params.Address,
BrokenChunks: nil,
})
}

//nolint:unparam,ireturn,nolintlint
func loadAndUnprotectWallet(nickname string, app *fyne.App) (*wallet.Wallet, middleware.Responder) {
wallet, err := wallet.Load(nickname)
if err != nil {
return operations.NewWebsiteCreatorUploadInternalServerError().
WithPayload(
&models.Error{
Code: errorCodeGetWallet,
Message: err.Error(),
})
return nil, createInternalServerError(errorCodeGetWallet, err.Error())
}

clearPassword, err := gui.AskPassword(wallet.Nickname, app)
if err != nil {
return createInternalServerError(ErrorCodeWalletCanceledAction, err.Error())
return nil, createInternalServerError(ErrorCodeWalletCanceledAction, err.Error())
}

if len(clearPassword) == 0 {
return nil, createInternalServerError(ErrorCodeWalletPasswordEmptyWebCreator, ErrorCodeWalletPasswordEmptyWebCreator)
}

err = wallet.Unprotect(clearPassword, 0)
if err != nil {
return operations.NewWebsiteCreatorUploadInternalServerError().
WithPayload(
&models.Error{
Code: errorCodeWalletWrongPassword,
Message: err.Error(),
})
return nil, createInternalServerError(errorCodeWalletWrongPassword, err.Error())
}

archive, err := io.ReadAll(params.Zipfile)
return wallet, nil
}

//nolint:unparam,ireturn,nolintlint
func readAndCheckArchive(zipFile io.ReadCloser, app *fyne.App) ([]byte, middleware.Responder) {
archive, err := io.ReadAll(zipFile)
if err != nil {
return operations.NewWebsiteCreatorUploadInternalServerError().
WithPayload(&models.Error{
Code: errorCodeWebCreatorReadArchive,
Message: err.Error(),
})
return nil, createInternalServerError(errorCodeWebCreatorReadArchive, err.Error())
}

if !checkContentType(archive, "application/zip") {
return createInternalServerError(errorCodeWebCreatorFileType, errorCodeWebCreatorFileType)
maxArchiveSize := GetMaxArchiveSize()

if len(archive) > maxArchiveSize {
return nil, createInternalServerError(errorCodeWebCreatorArchiveSize, errorCodeWebCreatorArchiveSize)
}

_, err = website.UploadMissedChunks(params.Address, archive, wallet, params.MissedChunks)
if err != nil {
return createInternalServerError(errorCodeWebCreatorUpload, err.Error())
zipReader, _ := zip.NewReader(bytes.NewReader(archive), int64(len(archive)))
FilesOfArchive := listFileName(zipReader)

if slices.Index(FilesOfArchive, "index.html") == -1 {
return nil, createInternalServerError(errorCodeWebCreatorHTMLNotInSource, errorCodeWebCreatorHTMLNotInSource)
}

return operations.NewWebsiteUploadMissingChunksOK().
WithPayload(&models.Websites{
Name: "Name",
Address: params.Address,
BrokenChunks: nil,
})
if !checkContentType(archive, "application/zip") {
return nil, createInternalServerError(errorCodeWebCreatorFileType, errorCodeWebCreatorFileType)
}

return archive, nil
}
23 changes: 23 additions & 0 deletions pkg/convert/byteConverter.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,26 @@ func BytesToString(entry []byte) string {

return string(content)
}

func ByteToStringArray(entry []byte) []string {
var result []string

content := entry
// with args you will have at least 5 bytes for a string (4 for the size and 1 for the value)
minimumNbBytes := bytesPerUint32 + 1
// we parse the content until there is no more string left inside
for len(content) >= minimumNbBytes {
// we check the string length and we update the offset
stringLength := binary.LittleEndian.Uint32(content[:bytesPerUint32])
offset := bytesPerUint32 + int(stringLength)

str := string(content[bytesPerUint32:offset])

result = append(result, str)

// we remove the string and its length header from the content
content = content[bytesPerUint32+int(stringLength):]
}

return result
}
Loading