From 2eed92514ee0ee279ad843038baeb9b96fdc743f Mon Sep 17 00:00:00 2001 From: Amy Waliszewska Date: Fri, 2 Aug 2024 17:27:49 +0200 Subject: [PATCH 01/10] 2-cat-gifs edit problem copy --- problems/2-cat-gifs/problem.md | 38 +++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/problems/2-cat-gifs/problem.md b/problems/2-cat-gifs/problem.md index ec1676d..51305fb 100644 --- a/problems/2-cat-gifs/problem.md +++ b/problems/2-cat-gifs/problem.md @@ -1,22 +1,46 @@ -# Storing cat gifs for fun and gossip +# Storing cat memes for fun and gossip -These cat gifs are not going to store themselves. Lets hurl them into the permanent web where they can be revered **forever**. +These cat memes of yours are not going to store themselves. Let's catapult them into the permanent web where they can be adored **forever**. But wait, what did you just say? Permanent web? Yeah, like IPFS. -IPFS uses content addressing (sometimes known as hash addressing) where you refer to data by a "hash" that is created from the data itself. If the data changes, the hash changes. Anyone can store and distribute your data because the hash guarantees the data cannot change. Imagine the caching possibilities! +**What is the Permanent Web?** -In the third web, you hash your content _first_, that way you know the hash you generated refers to the content you generated it from, and if you fetch the content by it's hash, you can verify that the content you receive hasn't been tampered with because it "hashes" to the same value. +Imagine a world where your favorite cat memes are preserved forever. That's the magic of IPFS (InterPlanetary File System). IPFS uses content addressing, a fancy way of saying you refer to data by a "hash" created from the data itself. If the data changes, the hash changes too. This ensures that the data remains unchanged and untampered with. Think of it as a digital fingerprint for your memes! -In IPFS, hashes are referred to as Content Identifiers, or CID for short. In this exercise we're going to transform your data into content addressed data, that you can refer to via a CID, upload it to web3.storage and print out the CID. +**Why Content Addressing?** -Create a _new_ file for your solution e.g. `ex3.mjs`. Import the w3up library and create the client as before. Install the module `files-from-path` from npm (`npm install files-from-path`) and import it like so: +On the third web, you hash your content first. This means the hash you generate is unique to the content you created. If you fetch the content by its hash, you can be sure that the content hasn't been tampered with because it "hashes" to the same value. It's like a super-secure way to keep your cat memes pristine and perfect. + +**Let's Get Started!** + +We're going to transform your cat memes into content-addressed data, upload them to web3.storage, and print out their unique CID (Content Identifier). Once you downloaded the last meme your friend sent you, continue with: + +**1. Create a New File** +Create a _new_ file, like `ex3.mjs`. +**2. Import w3up and create the client** +Import the w3up library and create the client as before. +**3. Instal the `files-from-path`** +It helps read files from your local file system and transforms file paths into a format that can be uploaded to web3.storage. Without this module, you’d be stuck doing all the heavy lifting of file reading and formatting. And who has time for it in this economy? +Install `npm install files-from-path` and import ```js import { filesFromPaths } from 'files-from-path' ``` +**4. Upload the meme** +Specify the path to the meme: +```js +const files = await filesFromPaths(['path-to-your-meme']) +``` +and upload it with using function uploadDirectory on client: +```js +const root = await client.uploadDirectory(files); +``` -Use the `uploadDirectory` function on the client to upload you favourite cat gif from your local file system to web3.storage. You'll receive a CID for the content, use `console.log` to print it out. +End with printing CID console.log(root.toString()); +```js +console.log(root.toString()); +``` ───────────────────────────────────────────────────────────────────────────── * To print these instructions again, run: `$ADVENTURE_NAME print` From 1c1a6d43f2819cef3dbff99cf391db64f877d629 Mon Sep 17 00:00:00 2001 From: Amy Waliszewska Date: Mon, 5 Aug 2024 12:47:42 +0200 Subject: [PATCH 02/10] 3-delegation problem updated --- problems/3-delegation/problem.md | 50 +++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/problems/3-delegation/problem.md b/problems/3-delegation/problem.md index d307201..edbd3f9 100644 --- a/problems/3-delegation/problem.md +++ b/problems/3-delegation/problem.md @@ -4,11 +4,14 @@ Excellent cat gifs. Well done you. Now, lets talk UCAN. -UCANs are like JWTs with super powers. They’re an essential component in decentralized authorization. They use public key cryptography - so whenever you create a UCAN you _sign it_ with your private key. +**What are UCANs?** +UCANs (User Controlled Authorization Networks) are like supercharged passwords. They’re used for secure, decentralized authorization. When you create a UCAN, you sign it with your private key, kind of like signing a document with your unique signature. -The best thing about UCANs is that you can provably delegate "capabilities" that allow others to act on your behalf, without ever sharing your private key. +**What are UCANs cool?** +The best thing about UCANs is that you can securely give permission to others to do things on your behalf without sharing your private key. This is called "delegation." -In this exercise, you're going to delegate an `upload/list` capability to the workshop. Behind the scenes the workshop will create it's own private key, and pass it's public key (it's DID) to you on `stdin`. +**Your Mission** +In this exercise, you're going to delegate an upload/list capability to the workshop. The workshop will create its own private key and pass its public key (DID) to you through stdin (standard input). Your program should read from `process.stdin`, create a delegation for the `upload/list` capability and write it to `process.stdout`. So, something like this: @@ -18,8 +21,12 @@ DID => your program => delegation Then the workshop will be able to **invoke** the capability to list the items _you've_ uploaded to _your_ space. It'll verify it can find that cat gif you uploaded in the previous exercise. -You can read and parse the DID from `stdin` like so: +One last thing, make sure the delegation remains valid for **more than one hour**. + +**Steps to complete the task** +**1. Create new file and read DID from stdin** +Create new file, like `ex4.mjs` and then you can read and parse the DID from 'process.stdin': ```js import fs from 'node:fs' import * as DID from '@ipld/dag-ucan/did' @@ -27,11 +34,40 @@ import * as DID from '@ipld/dag-ucan/did' const data = fs.readFileSync(process.stdin.fd, 'utf-8') const principal = DID.parse(data) ``` +**2. Create the delegetion** +Use the client to create a delegation for upload/list to the provided DID: +```js +import * as Client from '@web3-storage/w3up-client'; +``` +Create the client and set the expiration time for the delegation: +```js +const client = await Client.create(); +const twoHours = 1000 * 60 * 60 * 2; // Two hours in milliseconds +``` +In the example above, it is set to two hours. +**3. Generate the delegation** +Create the delegation for the upload/list capability: +```js +const delegation = await client.createDelegation(principal, ['upload/list'], { + // Expiration is in seconds from Unix epoch + expiration: Math.round((Date.now() + twoHours) / 1000), +}); +``` -Create a _new_ file for your solution e.g. `ex4.mjs` and use the client to create a delegation for `upload/list` to the provided DID. Create an archive of the delegation and write it to `process.stdout`. - -One last thing, make sure the delegation remains valid for **more than one hour**. +**4. Archive the delegation** +Archive the delegation and handle any errors: +```js +const { ok: archive, error } = await delegation.archive(); +if (!archive) { + throw new Error('Failed to create delegation archive', { cause: error }); +} +``` +**5. Output the delegation** +Write the delegation to `process.stdout`: + ```js + process.stdout.write(archive); + ``` ───────────────────────────────────────────────────────────────────────────── * To print these instructions again, run: `$ADVENTURE_NAME print` * To verify your program, run: `$ADVENTURE_NAME verify ex4.mjs` From febef903dce9f5c0ce7a7bee86bd711cc3c4f005 Mon Sep 17 00:00:00 2001 From: Amy Waliszewska Date: Mon, 5 Aug 2024 15:06:24 +0200 Subject: [PATCH 03/10] challenge 2 and 3 - updated PR feedback --- problems/3-delegation/problem.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/problems/3-delegation/problem.md b/problems/3-delegation/problem.md index edbd3f9..66ff0bf 100644 --- a/problems/3-delegation/problem.md +++ b/problems/3-delegation/problem.md @@ -7,11 +7,11 @@ Now, lets talk UCAN. **What are UCANs?** UCANs (User Controlled Authorization Networks) are like supercharged passwords. They’re used for secure, decentralized authorization. When you create a UCAN, you sign it with your private key, kind of like signing a document with your unique signature. -**What are UCANs cool?** -The best thing about UCANs is that you can securely give permission to others to do things on your behalf without sharing your private key. This is called "delegation." +**Why are UCANs cool?** +The best thing about UCANs is that you can securely give permission to others to do things on your behalf without sharing your private key. This is called "delegation". **Your Mission** -In this exercise, you're going to delegate an upload/list capability to the workshop. The workshop will create its own private key and pass its public key (DID) to you through stdin (standard input). +In this exercise, you're going to delegate an `upload/list` capability to the workshop. The workshop will create its own private key and pass its public key (DID) to you via `stdin` (standard input). Your program should read from `process.stdin`, create a delegation for the `upload/list` capability and write it to `process.stdout`. So, something like this: @@ -25,8 +25,8 @@ One last thing, make sure the delegation remains valid for **more than one hour* **Steps to complete the task** -**1. Create new file and read DID from stdin** -Create new file, like `ex4.mjs` and then you can read and parse the DID from 'process.stdin': +**1. Create new file and read a DID from `stdin`** +Create new file, like `ex4.mjs` and then you can read and parse the DID from `process.stdin`: ```js import fs from 'node:fs' import * as DID from '@ipld/dag-ucan/did' @@ -35,38 +35,38 @@ const data = fs.readFileSync(process.stdin.fd, 'utf-8') const principal = DID.parse(data) ``` **2. Create the delegetion** -Use the client to create a delegation for upload/list to the provided DID: +Use the client to create a delegation for `upload/list` to the provided DID: ```js -import * as Client from '@web3-storage/w3up-client'; +import * as Client from '@web3-storage/w3up-client' ``` Create the client and set the expiration time for the delegation: ```js -const client = await Client.create(); -const twoHours = 1000 * 60 * 60 * 2; // Two hours in milliseconds +const client = await Client.create() +const twoHours = 1000 * 60 * 60 * 2 // Two hours in milliseconds ``` In the example above, it is set to two hours. **3. Generate the delegation** -Create the delegation for the upload/list capability: +Create the delegation for the `upload/list` capability: ```js const delegation = await client.createDelegation(principal, ['upload/list'], { // Expiration is in seconds from Unix epoch expiration: Math.round((Date.now() + twoHours) / 1000), -}); +}) ``` **4. Archive the delegation** Archive the delegation and handle any errors: ```js -const { ok: archive, error } = await delegation.archive(); +const { ok: archive, error } = await delegation.archive() if (!archive) { - throw new Error('Failed to create delegation archive', { cause: error }); + throw new Error('Failed to create delegation archive', { cause: error }) } ``` **5. Output the delegation** Write the delegation to `process.stdout`: ```js - process.stdout.write(archive); + process.stdout.write(archive) ``` ───────────────────────────────────────────────────────────────────────────── * To print these instructions again, run: `$ADVENTURE_NAME print` From f546870e6a78799b67c43f5876f32dd17b001b1e Mon Sep 17 00:00:00 2001 From: Amy Waliszewska Date: Mon, 5 Aug 2024 15:28:37 +0200 Subject: [PATCH 04/10] update --- problems/2-cat-gifs/problem.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/problems/2-cat-gifs/problem.md b/problems/2-cat-gifs/problem.md index 51305fb..7376899 100644 --- a/problems/2-cat-gifs/problem.md +++ b/problems/2-cat-gifs/problem.md @@ -14,15 +14,15 @@ On the third web, you hash your content first. This means the hash you generate **Let's Get Started!** -We're going to transform your cat memes into content-addressed data, upload them to web3.storage, and print out their unique CID (Content Identifier). Once you downloaded the last meme your friend sent you, continue with: +Download a meme locally (or use the one that you already have!), upload them to web3.storage, and print out their unique CID (Content Identifier). Once you downloaded the last meme your friend sent you, continue with: **1. Create a New File** Create a _new_ file, like `ex3.mjs`. **2. Import w3up and create the client** Import the w3up library and create the client as before. -**3. Instal the `files-from-path`** -It helps read files from your local file system and transforms file paths into a format that can be uploaded to web3.storage. Without this module, you’d be stuck doing all the heavy lifting of file reading and formatting. And who has time for it in this economy? -Install `npm install files-from-path` and import +**3. Instal the `files-from-path` module** +It helps read files from your local file system and transforms file paths into a format that can be uploaded to web3.storage. Without this module, you’d be stuck doing all the heavy lifting of file reading and formatting - who has time for that in this economy? +Install `npm install files-from-path` and import: ```js import { filesFromPaths } from 'files-from-path' @@ -32,14 +32,14 @@ Specify the path to the meme: ```js const files = await filesFromPaths(['path-to-your-meme']) ``` -and upload it with using function uploadDirectory on client: +and upload it with using the client's `uploadDirectory` function: ```js -const root = await client.uploadDirectory(files); +const root = await client.uploadDirectory(files) ``` -End with printing CID console.log(root.toString()); +Finally, print the CID: ```js -console.log(root.toString()); +console.log(root.toString()) ``` ───────────────────────────────────────────────────────────────────────────── From 2dfbe3dcab17fc87e667a521f03894ff30dc9583 Mon Sep 17 00:00:00 2001 From: Amy Waliszewska <69154712+hakierka@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:52:58 +0200 Subject: [PATCH 05/10] Update problems/2-cat-gifs/problem.md Co-authored-by: Alan Shaw --- problems/2-cat-gifs/problem.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/problems/2-cat-gifs/problem.md b/problems/2-cat-gifs/problem.md index 7376899..1412cb5 100644 --- a/problems/2-cat-gifs/problem.md +++ b/problems/2-cat-gifs/problem.md @@ -20,7 +20,7 @@ Download a meme locally (or use the one that you already have!), upload them to Create a _new_ file, like `ex3.mjs`. **2. Import w3up and create the client** Import the w3up library and create the client as before. -**3. Instal the `files-from-path` module** +**3. Install the `files-from-path` module** It helps read files from your local file system and transforms file paths into a format that can be uploaded to web3.storage. Without this module, you’d be stuck doing all the heavy lifting of file reading and formatting - who has time for that in this economy? Install `npm install files-from-path` and import: From 8887f2ac6790d7f2f896239d3ab3180042989abd Mon Sep 17 00:00:00 2001 From: Amy Waliszewska <69154712+hakierka@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:53:17 +0200 Subject: [PATCH 06/10] Update problems/3-delegation/problem.md Co-authored-by: Alan Shaw --- problems/3-delegation/problem.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/problems/3-delegation/problem.md b/problems/3-delegation/problem.md index 66ff0bf..72b3759 100644 --- a/problems/3-delegation/problem.md +++ b/problems/3-delegation/problem.md @@ -19,7 +19,7 @@ Your program should read from `process.stdin`, create a delegation for the `uplo DID => your program => delegation ``` -Then the workshop will be able to **invoke** the capability to list the items _you've_ uploaded to _your_ space. It'll verify it can find that cat gif you uploaded in the previous exercise. +Then the workshop will be able to **invoke** the capability to list the items _you've_ uploaded to _your_ space. It'll verify it can find that cat meme you uploaded in the previous exercise. One last thing, make sure the delegation remains valid for **more than one hour**. From 94a3a46f9653ab68523af3ab23cf7908f9df5c6e Mon Sep 17 00:00:00 2001 From: Amy Waliszewska <69154712+hakierka@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:56:29 +0200 Subject: [PATCH 07/10] Update bin.js --- bin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin.js b/bin.js index 77648d4..7e781bd 100755 --- a/bin.js +++ b/bin.js @@ -18,7 +18,7 @@ const shop = adventure({ shop.add('Introduction: UCAN do it!', () => IntroductionProblem) shop.add('Lets space out', () => SpaceOutProblem) -shop.add('Storing cat gifs for fun and gossip', () => CatGifsProblem) +shop.add('Storing cat memes for fun and gossip', () => CatMemesProblem) shop.add('Delegation, invocation and procrastination', () => DelegationProblem) shop.add('Infinite avatar compression!', () => InfiniteCompressionProblem) shop.add('Memes for my eyes', () => MemesProblem) From 3c7be0d87628781fe6cf5079a474850277aebc8b Mon Sep 17 00:00:00 2001 From: Amy Waliszewska <69154712+hakierka@users.noreply.github.com> Date: Mon, 5 Aug 2024 17:59:42 +0200 Subject: [PATCH 08/10] Update problem.md --- problems/4-infinite-compression/problem.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/problems/4-infinite-compression/problem.md b/problems/4-infinite-compression/problem.md index 5d6ac9b..43ea660 100644 --- a/problems/4-infinite-compression/problem.md +++ b/problems/4-infinite-compression/problem.md @@ -14,7 +14,7 @@ In web3.storage, we content address CARs as well! So we generate a hash for the I know loads of text, but one more thing, sometimes y'all got big datas. If the datas are big, we split the DAG across multiple CAR files. In this exercise we're going to store something else and log out the CAR CIDs a.k.a. the CID of the CAR _shards_. -Create a _new_ file for your solution e.g. `ex5.mjs` and upload something like you did in the cat gifs exercise. This time though, print out the CIDs of the CAR shards as they are sent, and then _finally_ the CID of the root of the DAG. Your output is expected to be newline delimited. +Create a _new_ file for your solution e.g. `ex5.mjs` and upload something like you did in the cat memes exercise. This time though, print out the CIDs of the CAR shards as they are sent, and then _finally_ the CID of the root of the DAG. Your output is expected to be newline delimited. Good luck! From d7c54c65008512e02ce2403e75b814f622dcd7e0 Mon Sep 17 00:00:00 2001 From: Amy Waliszewska <69154712+hakierka@users.noreply.github.com> Date: Mon, 5 Aug 2024 18:00:15 +0200 Subject: [PATCH 09/10] Update problem.md --- problems/3-delegation/problem.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/problems/3-delegation/problem.md b/problems/3-delegation/problem.md index 72b3759..92d99dc 100644 --- a/problems/3-delegation/problem.md +++ b/problems/3-delegation/problem.md @@ -1,6 +1,6 @@ # Delegation, invocation and procrastination -Excellent cat gifs. Well done you. +Excellent cat memes. Well done you. Now, lets talk UCAN. From 4bea3b85f05efe1aaab18a349e726c8bdd92b1f3 Mon Sep 17 00:00:00 2001 From: Amy Waliszewska <69154712+hakierka@users.noreply.github.com> Date: Mon, 5 Aug 2024 18:04:07 +0200 Subject: [PATCH 10/10] Update bin.js --- bin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin.js b/bin.js index 7e781bd..b987546 100755 --- a/bin.js +++ b/bin.js @@ -2,7 +2,7 @@ import adventure from 'adventure' import * as IntroductionProblem from './problems/0-introduction/index.js' import * as SpaceOutProblem from './problems/1-space-out/index.js' -import * as CatGifsProblem from './problems/2-cat-gifs/index.js' +import * as CatMemesProblem from './problems/2-cat-gifs/index.js' import * as DelegationProblem from './problems/3-delegation/index.js' import * as InfiniteCompressionProblem from './problems/4-infinite-compression/index.js' import * as MemesProblem from './problems/5-memes/index.js'