// Copyright 2024 The Update Framework Authors
//
// 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
//
// SPDX-License-Identifier: Apache-2.0
//

package main

import (
	"crypto"
	"crypto/ecdsa"
	"crypto/ed25519"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/rsa"
	"fmt"
	"os"
	"path/filepath"
	"time"

	"github.com/sigstore/sigstore/pkg/signature"
	"github.com/theupdateframework/go-tuf/v2/examples/repository/repository"
	"github.com/theupdateframework/go-tuf/v2/metadata"
)

// A TUF repository example using the low-level TUF Metadata API.

// The example code in this file demonstrates how to *manually* create and
// maintain repository metadata using the low-level Metadata API.
// Contents:
//  * creation of top-level metadata
//  * target file handling
//  * consistent snapshots
//  * key management
//  * top-level delegation and signing thresholds
//  * metadata verification
//  * target delegation
//  * in-band and out-of-band metadata signing
//  * writing and reading metadata files
//  * root key rotation

// NOTE: Metadata files will be written to a 'tmp*'-directory in CWD.

func main() {
	// Create top-level metadata
	// =========================
	// Every TUF repository has at least four roles, i.e. the top-level roles
	// 'targets', 'snapshot', 'timestamp' and 'root'. Below we will discuss their
	// purpose, show how to create the corresponding metadata, and how to use them
	// to provide integrity, consistency and freshness for the files TUF aims to
	// protect, i.e. target files.

	// Define containers for metadata objects and cryptographic keys created below. This
	// allows us to sign and write metadata in a batch more easily. The repository.New() instance
	// doesn't provide anything else yet other than serving as a placeholder for all metadata.
	roles := repository.New()
	keys := map[string]ed25519.PrivateKey{}

	// Targets (integrity)
	// -------------------
	// The targets role guarantees integrity for the files that TUF aims to protect,
	// i.e. target files. It does so by listing the relevant target files, along
	// with their hash and length.
	targets := metadata.Targets(helperExpireIn(7))
	roles.SetTargets("targets", targets)

	// For the purpose of this example we use the top-level targets role to protect
	// the integrity of this very example script. The metadata entry contains the
	// hash and length of this file at the local path. In addition, it specifies the
	// 'target path', which a client uses to locate the target file relative to a
	// configured mirror base URL.
	//     |----base URL---||--------target path--------|
	// e.g. tuf-examples.org/examples/basic_repository.py
	targetPath, localPath := helperGetPathForTarget("basic_repository.go")
	targetFileInfo, err := metadata.TargetFile().FromFile(localPath, "sha256")
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "generating target file info failed", err))
	}
	roles.Targets("targets").Signed.Targets[targetPath] = targetFileInfo

	// Snapshot (consistency)
	// ----------------------
	// The snapshot role guarantees consistency of the entire repository. It does so
	// by listing all available targets metadata files at their latest version. This
	// becomes relevant, when there are multiple targets metadata files in a
	// repository and we want to protect the client against mix-and-match attacks.
	snapshot := metadata.Snapshot(helperExpireIn(7))
	roles.SetSnapshot(snapshot)

	// Timestamp (freshness)
	// ---------------------
	// The timestamp role guarantees freshness of the repository metadata. It does
	// so by listing the latest snapshot (which in turn lists all the latest
	// targets) metadata. A short expiration interval requires the repository to
	// regularly issue new timestamp metadata and thus protects the client against
	// freeze attacks.
	// Note that snapshot and timestamp use the same generic wireline metadata
	// format.
	timestamp := metadata.Timestamp(helperExpireIn(1))
	roles.SetTimestamp(timestamp)

	// Root (root of trust)
	// --------------------
	// The root role serves as root of trust for all top-level roles, including
	// itself. It does so by mapping cryptographic keys to roles, i.e. the keys that
	// are authorized to sign any top-level role metadata, and signing thresholds,
	// i.e. how many authorized keys are required for a given role (see 'roles'
	// field). This is called top-level delegation.

	// In addition, root provides all public keys to verify these signatures (see
	// 'keys' field), and a configuration parameter that describes whether a
	// repository uses consistent snapshots (see section 'Persist metadata' below
	// for more details).

	// Create root metadata object
	root := metadata.Root(helperExpireIn(365))
	roles.SetRoot(root)

	// For this example, we generate one private key of type 'ed25519' for each top-level role
	for _, name := range []string{"targets", "snapshot", "timestamp", "root"} {
		_, private, err := ed25519.GenerateKey(nil)
		if err != nil {
			panic(fmt.Sprintln("basic_repository.go:", "key generation failed", err))
		}
		keys[name] = private
		key, err := metadata.KeyFromPublicKey(private.Public())
		if err != nil {
			panic(fmt.Sprintln("basic_repository.go:", "key conversion failed", err))
		}
		err = roles.Root().Signed.AddKey(key, name)
		if err != nil {
			panic(fmt.Sprintln("basic_repository.go:", "adding key to root failed", err))
		}
	}
	// NOTE: We only need the public part to populate root, so it is possible to use
	// out-of-band mechanisms to generate key pairs and only expose the public part
	// to whoever maintains the root role. As a matter of fact, the very purpose of
	// signature thresholds is to avoid having private keys all in one place.

	// Signature thresholds
	// --------------------
	// Given the importance of the root role, it is highly recommended to require a
	// threshold of multiple keys to sign root metadata. For this example we
	// generate another root key (you can pretend it's out-of-band) and increase the
	// required signature threshold.
	_, anotherRootKey, err := ed25519.GenerateKey(nil)
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "key generation failed", err))
	}

	anotherKey, err := metadata.KeyFromPublicKey(anotherRootKey.Public())
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "key conversion failed", err))
	}
	err = roles.Root().Signed.AddKey(anotherKey, "root")
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "adding another key to root failed", err))
	}
	roles.Root().Signed.Roles["root"].Threshold = 2

	// Sign top-level metadata (in-band)
	// =================================
	// In this example we have access to all top-level signing keys, so we can use
	// them to create and add a signature for each role metadata.
	for _, name := range []string{"targets", "snapshot", "timestamp", "root"} {
		key := keys[name]
		signer, err := signature.LoadSigner(key, crypto.Hash(0))
		if err != nil {
			panic(fmt.Sprintln("basic_repository.go:", "loading a signer failed", err))
		}
		switch name {
		case "targets":
			_, err = roles.Targets("targets").Sign(signer)
		case "snapshot":
			_, err = roles.Snapshot().Sign(signer)
		case "timestamp":
			_, err = roles.Timestamp().Sign(signer)
		case "root":
			_, err = roles.Root().Sign(signer)
		}
		if err != nil {
			panic(fmt.Sprintln("basic_repository.go:", "metadata signing failed", err))
		}
	}

	// Persist metadata (consistent snapshot)
	// ======================================
	// It is time to publish the first set of metadata for a client to safely
	// download the target file that we have registered for this example repository.

	// For the purpose of this example we will follow the consistent snapshot naming
	// convention for all metadata. This means that each metadata file, must be
	// prefixed with its version number, except for timestamp. The naming convention
	// also affects the target files, but we don't cover this in the example. See
	// the TUF specification for more details:
	// https://theupdateframework.github.io/specification/latest/#writing-consistent-snapshots

	// Also note that the TUF specification does not mandate a wireline format. In
	// this demo we use a non-compact JSON format and store all metadata in
	// temporary directory at CWD for review.
	cwd, err := os.Getwd()
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "getting cwd failed", err))
	}
	tmpDir, err := os.MkdirTemp(cwd, "tmp")
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "creating a temporary folder failed", err))
	}

	for _, name := range []string{"targets", "snapshot", "timestamp", "root"} {
		switch name {
		case "targets":
			filename := fmt.Sprintf("%d.%s.json", roles.Targets("targets").Signed.Version, name)
			err = roles.Targets("targets").ToFile(filepath.Join(tmpDir, filename), true)
		case "snapshot":
			filename := fmt.Sprintf("%d.%s.json", roles.Snapshot().Signed.Version, name)
			err = roles.Snapshot().ToFile(filepath.Join(tmpDir, filename), true)
		case "timestamp":
			filename := fmt.Sprintf("%s.json", name)
			err = roles.Timestamp().ToFile(filepath.Join(tmpDir, filename), true)
		case "root":
			filename := fmt.Sprintf("%d.%s.json", roles.Root().Signed.Version, name)
			err = roles.Root().ToFile(filepath.Join(tmpDir, filename), true)
		}
		if err != nil {
			panic(fmt.Sprintln("basic_repository.go:", "saving metadata to file failed", err))
		}
	}

	// Threshold signing (out-of-band)
	// ===============================
	// As mentioned above, using signature thresholds usually entails that not all
	// signing keys for a given role are in the same place. Let's briefly pretend
	// this is the case for the second root key we registered above, and we are now
	// on that key owner's computer. All the owner has to do is read the metadata
	// file, sign it, and write it back to the same file, and this can be repeated
	// until the threshold is satisfied.
	_, err = roles.Root().FromFile(filepath.Join(tmpDir, "1.root.json"))
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "loading root metadata from file failed", err))
	}
	outofbandSigner, err := signature.LoadSigner(anotherRootKey, crypto.Hash(0))
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "loading a signer failed", err))
	}
	_, err = roles.Root().Sign(outofbandSigner)
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "signing root failed", err))
	}
	err = roles.Root().ToFile(filepath.Join(tmpDir, "1.root.json"), true)
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "saving root metadata to file failed", err))
	}

	// Verify that metadata is signed correctly
	// ====================================
	// Verify root
	err = roles.Root().VerifyDelegate("root", roles.Root())
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "verifying root metadata failed", err))
	}

	// Verify targets
	err = roles.Root().VerifyDelegate("targets", roles.Targets("targets"))
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "verifying targets metadata failed", err))
	}

	// Verify snapshot
	err = roles.Root().VerifyDelegate("snapshot", roles.Snapshot())
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "verifying snapshot metadata failed", err))
	}

	// Verify timestamp
	err = roles.Root().VerifyDelegate("timestamp", roles.Timestamp())
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "verifying timestamp metadata failed", err))
	}

	// Targets delegation
	// ==================
	// Similar to how the root role delegates responsibilities about integrity,
	// consistency and freshness to the corresponding top-level roles, a targets
	// role may further delegate its responsibility for target files (or a subset
	// thereof) to other targets roles. This allows creation of a granular trust
	// hierarchy, and further reduces the impact of a single role compromise.

	// In this example the top-level targets role trusts a new "go-scripts"
	// targets role to provide integrity for any target file that ends with ".go".
	delegateeName := "go-scripts"
	_, delegateePrivateKey, err := ed25519.GenerateKey(nil)
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "key generation failed", err))
	}
	keys[delegateeName] = delegateePrivateKey

	// Delegatee
	// ---------
	// Create a new targets role, akin to how we created top-level targets above, and
	// add target file info from above according to the delegatee's responsibility.
	delegatee := metadata.Targets(helperExpireIn(7))
	delegatee.Signed.Targets[targetPath] = targetFileInfo
	roles.SetTargets(delegateeName, delegatee)

	// Delegator
	// ---------
	// Akin to top-level delegation, the delegator expresses its trust in the
	// delegatee by authorizing a threshold of cryptographic keys to provide
	// signatures for the delegatee metadata. It also provides the corresponding
	// public key store.
	// The delegation info defined by the delegator further requires the provision
	// of a unique delegatee name and constraints about the target files the
	// delegatee is responsible for, e.g. a list of path patterns. For details about
	// all configuration parameters see
	// https://theupdateframework.github.io/specification/latest/#delegations
	delegateeKey, _ := metadata.KeyFromPublicKey(delegateePrivateKey.Public())
	delegateeKeyID, err := delegateeKey.ID()
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "failed to get key ID", err))
	}
	roles.Targets("targets").Signed.Delegations = &metadata.Delegations{
		Keys: map[string]*metadata.Key{
			delegateeKeyID: delegateeKey,
		},
		Roles: []metadata.DelegatedRole{
			{
				Name:        delegateeName,
				KeyIDs:      []string{delegateeKeyID},
				Threshold:   1,
				Terminating: true,
				Paths:       []string{"*.go"},
			},
		},
	}

	// Remove target file info from top-level targets (delegatee is now responsible)
	delete(roles.Targets("targets").Signed.Targets, targetPath)

	// Increase expiry (delegators should be less volatile)
	roles.Targets("targets").Signed.Expires = helperExpireIn(365)

	// Snapshot + Timestamp + Sign + Persist
	// -------------------------------------
	// In order to publish a new consistent set of metadata, we need to update
	// dependent roles (snapshot, timestamp) accordingly, bumping versions of all
	// changed metadata.

	// Bump targets version
	roles.Targets("targets").Signed.Version += 1

	// Update snapshot to account for changed and new targets(delegatee) metadata
	roles.Snapshot().Signed.Meta["targets.json"] = metadata.MetaFile(roles.Targets("targets").Signed.Version)
	roles.Snapshot().Signed.Meta[fmt.Sprintf("%s.json", delegateeName)] = metadata.MetaFile(1)
	roles.Snapshot().Signed.Version += 1

	// Update timestamp to account for changed snapshot metadata
	roles.Timestamp().Signed.Meta["snapshot.json"] = metadata.MetaFile(roles.Snapshot().Signed.Version)
	roles.Timestamp().Signed.Version += 1

	// Sign and write metadata for all changed roles, i.e. all but root
	for _, name := range []string{"targets", "snapshot", "timestamp", delegateeName} {
		key := keys[name]
		signer, err := signature.LoadSigner(key, crypto.Hash(0))
		if err != nil {
			panic(fmt.Sprintln("basic_repository.go:", "loading a signer failed", err))
		}
		switch name {
		case "targets":
			roles.Targets("targets").ClearSignatures()
			_, err = roles.Targets("targets").Sign(signer)
			if err != nil {
				panic(fmt.Sprintln("basic_repository.go:", "signing metadata failed", err))
			}
			filename := fmt.Sprintf("%d.%s.json", roles.Targets("targets").Signed.Version, name)
			err = roles.Targets("targets").ToFile(filepath.Join(tmpDir, filename), true)
		case "snapshot":
			roles.Snapshot().ClearSignatures()
			_, err = roles.Snapshot().Sign(signer)
			if err != nil {
				panic(fmt.Sprintln("basic_repository.go:", "signing metadata failed", err))
			}
			filename := fmt.Sprintf("%d.%s.json", roles.Snapshot().Signed.Version, name)
			err = roles.Snapshot().ToFile(filepath.Join(tmpDir, filename), true)
		case "timestamp":
			roles.Timestamp().ClearSignatures()
			_, err = roles.Timestamp().Sign(signer)
			if err != nil {
				panic(fmt.Sprintln("basic_repository.go:", "signing metadata failed", err))
			}
			filename := fmt.Sprintf("%s.json", name)
			err = roles.Timestamp().ToFile(filepath.Join(tmpDir, filename), true)
		case delegateeName:
			roles.Targets(delegateeName).ClearSignatures()
			_, err = roles.Targets(delegateeName).Sign(signer)
			if err != nil {
				panic(fmt.Sprintln("basic_repository.go:", "signing metadata failed", err))
			}
			filename := fmt.Sprintf("%d.%s.json", roles.Targets(delegateeName).Signed.Version, name)
			err = roles.Targets(delegateeName).ToFile(filepath.Join(tmpDir, filename), true)
		}
		if err != nil {
			panic(fmt.Sprintln("basic_repository.go:", "saving metadata to file failed", err))
		}
	}

	// Root key rotation (recover from a compromise / key loss)
	// ========================================================
	// TUF makes it easy to recover from a key compromise in-band. Given the trust
	// hierarchy through top-level and targets delegation you can easily
	// replace compromised or lost keys for any role using the delegating role, even
	// for the root role.
	// However, since root authorizes its own keys, it always has to be signed with
	// both the threshold of keys from the previous version and the threshold of
	// keys from the new version. This establishes a trusted line of continuity.

	// In this example we will replace a root key, and sign a new version of root
	// with the threshold of old and new keys. Since one of the previous root keys
	// remains in place, it can be used to count towards the old and new threshold.
	_, newRootKey, err := ed25519.GenerateKey(nil)
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "key generation failed", err))
	}
	oldRootKey, err := metadata.KeyFromPublicKey(keys["root"].Public())
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "key conversion failed", err))
	}
	oldRootKeyID, err := oldRootKey.ID()
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "failed to get key ID", err))
	}
	err = roles.Root().Signed.RevokeKey(oldRootKeyID, "root")
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "revoking key failed", err))
	}
	// Add new key for root
	newRootKeyTUF, err := metadata.KeyFromPublicKey(newRootKey.Public())
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "key conversion failed", err))
	}
	err = roles.Root().Signed.AddKey(newRootKeyTUF, "root")
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "adding key to root failed", err))
	}
	roles.Root().Signed.Version += 1
	roles.Root().ClearSignatures()

	// Sign root
	for _, k := range []ed25519.PrivateKey{keys["root"], anotherRootKey, newRootKey} {
		signer, err := signature.LoadSigner(k, crypto.Hash(0))
		if err != nil {
			panic(fmt.Sprintln("basic_repository.go:", "loading a signer failed", err))
		}
		_, err = roles.Root().Sign(signer)
		if err != nil {
			panic(fmt.Sprintln("basic_repository.go:", "signing root failed", err))
		}
	}
	filename := fmt.Sprintf("%d.%s.json", roles.Root().Signed.Version, "root")
	err = roles.Root().ToFile(filepath.Join(tmpDir, filename), true)
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "saving root to file failed", err))
	}

	// Verify again that metadata is signed correctly
	// ==============================================
	// Verify root
	err = roles.Root().VerifyDelegate("root", roles.Root())
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "verifying root metadata failed", err))
	}

	// Verify targets
	err = roles.Root().VerifyDelegate("targets", roles.Targets("targets"))
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "verifying targets metadata failed", err))
	}

	// Verify snapshot
	err = roles.Root().VerifyDelegate("snapshot", roles.Snapshot())
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "verifying snapshot metadata failed", err))
	}

	// Verify timestamp
	err = roles.Root().VerifyDelegate("timestamp", roles.Timestamp())
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "verifying timestamp metadata failed", err))
	}

	// Verify delegatee
	err = roles.Targets("targets").VerifyDelegate(delegateeName, roles.Targets(delegateeName))
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "verifying delegatee metadata failed", err))
	}

	// Use a mixture of key types
	// ==========================
	// Create an RSA key.
	// Note TUF should use an RSA PSS key scheme, not RSA PKCS1v15.
	// Reference: https://theupdateframework.github.io/specification/latest/#file-formats-keys
	anotherRootKeyRSA, _ := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "RSA key generation failed", err))
	}
	anotherKeyRSA, err := metadata.KeyFromPublicKey(anotherRootKeyRSA.Public())
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "RSA key conversion failed", err))
	}

	// Create an ECDSA key
	anotherRootKeyECDSA, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "ECDSA key generation failed", err))
	}
	anotherKeyECDSA, err := metadata.KeyFromPublicKey(anotherRootKeyECDSA.Public())
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "ECDSA key conversion failed", err))
	}

	// Add the RSA key to root keys
	err = roles.Root().Signed.AddKey(anotherKeyRSA, "root")
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "adding RSA key to root failed", err))
	}

	// Add the ECDSA key to root keys
	err = roles.Root().Signed.AddKey(anotherKeyECDSA, "root")
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "adding ECDSA key to root failed", err))
	}

	// Clear existing signatures, bump version and threshold
	roles.Root().Signed.Roles["root"].Threshold = 4
	roles.Root().Signed.Version += 1
	roles.Root().ClearSignatures()

	// Sign root with existing ed25519 keys
	for _, k := range []ed25519.PrivateKey{keys["root"], anotherRootKey, newRootKey} {
		signer, err := signature.LoadSigner(k, crypto.Hash(0))
		if err != nil {
			panic(fmt.Sprintln("basic_repository.go:", "loading a signer failed", err))
		}
		_, err = roles.Root().Sign(signer)
		if err != nil {
			panic(fmt.Sprintln("basic_repository.go:", "signing root failed", err))
		}
	}

	// Sign root with the new RSA and ECDSA keys
	outofbandSignerRSA, err := signature.LoadRSAPSSSigner(anotherRootKeyRSA, crypto.SHA256, &rsa.PSSOptions{Hash: crypto.SHA256})
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "loading RSA signer failed", err))
	}
	outofbandSignerECDSA, err := signature.LoadSigner(anotherRootKeyECDSA, crypto.SHA256)
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "loading ECDSA signer failed", err))
	}
	_, err = roles.Root().Sign(outofbandSignerRSA)
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "signing root failed", err))
	}
	_, err = roles.Root().Sign(outofbandSignerECDSA)
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "signing root failed", err))
	}

	// Verify that root is signed correctly
	// ====================================
	err = roles.Root().VerifyDelegate("root", roles.Root())
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "verifying root metadata failed", err))
	}

	// Save root to file
	filename = fmt.Sprintf("%d.%s.json", roles.Root().Signed.Version, "root")
	err = roles.Root().ToFile(filepath.Join(tmpDir, filename), true)
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "saving root to file failed", err))
	}
	fmt.Println("Done! Metadata files location:", tmpDir)
}

// helperExpireIn returns time offset by days
func helperExpireIn(days int) time.Time {
	return time.Now().AddDate(0, 0, days).UTC()
}

// helperGetPathForTarget returns local and target paths for target
func helperGetPathForTarget(name string) (string, string) {
	cwd, err := os.Getwd()
	if err != nil {
		panic(fmt.Sprintln("basic_repository.go:", "getting cwd failed", err))
	}
	// _, dir := filepath.Split(cwd)
	// return filepath.Join(dir, name), filepath.Join(cwd, name)
	return name, filepath.Join(cwd, name)
}
