├── .DS_Store ├── .gitignore ├── LICENSE ├── README.md ├── dist ├── ceramic.js ├── client.js ├── idx.js ├── index.js ├── integration.js ├── lit.js └── wallet.js ├── documentation ├── _howToUpdateDocs.md ├── ceramic.md ├── client.md ├── integration.md └── lit.md ├── notes.md ├── package-lock.json ├── package.json ├── src ├── ceramic.ts ├── client.ts ├── idx.ts ├── index.ts ├── integration.ts ├── lit.ts └── wallet.ts ├── tsconfig.json ├── typings-custom └── documentation.d.ts └── yarn.lock /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LIT-Protocol/CeramicIntegration/023d4cfd2166db0834d87f97f379ec936bbd01bb/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn-error.log -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Lit Protocol 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | - [Lit Ceramic Integration Module](#lit-ceramic-integration-module) 5 | - [Why?](#why) 6 | - [Motivation](#motivation) 7 | - [Installation](#installation) 8 | - [Usage](#usage) 9 | - [EVM Contract Conditions](#evm-contract-conditions) 10 | - [API Docs](#api-docs) 11 | - [Example](#example) 12 | - [More info](#more-info) 13 | - [To Do / Desired Future Features](#to-do--desired-future-features) 14 | - [Test Data](#test-data) 15 | - [Testing Ceramic Read Function](#testing-ceramic-read-function) 16 | 17 | 18 | 19 | # Lit Ceramic Integration Module 20 | 21 | ## Why? 22 | 23 | Ceramic is amazing, but doesn't have read permissions on data. Everything is public. With the Lit Protocol, you can specify who is able to decrypt and therefore read data based on on-chain conditions. This module allows you to integrate Ceramic with Lit. 24 | 25 | For example, you could use this as your DB for a website for a DAO you're a apart of, and specify that only DAO members can decrypt the data stored in Ceramic. 26 | 27 | ## Motivation 28 | 29 | The goal of this project is to provide a decentralized fully serverless database solution with the ability to easily share private data. Ceramic is a great solution for the decentralized serverless database, but it doesn't have the ability to share private data on it's own. This module will allow you to share private data on Ceramic with the ability to specify who can decrypt the data. 30 | 31 | ## Installation 32 | 33 | `yarn add lit-ceramic-sdk` 34 | 35 | ## Usage 36 | 37 | 1. Install as shown above 38 | 2. Import into your TS/JS where you'd like to use it. This is a typescript package as an FYI. 39 | 40 | Javascript requires minor amounts of extra work to use a Typescript project, [here's an example](https://www.freecodecamp.org/news/how-to-add-typescript-to-a-javascript-project/) of what that can look like, but there are plenty of good resources for this online. 41 | 42 | `import { Integration } from 'lit-ceramic-sdk'` 43 | 44 | 3. Create a new Integration that runs upon startup and is accessible where you intend to do encryptAndWrite or readAndDecrypt operations. Pass your Ceramic RPC URL and the chain you wish to use: 45 | `let litCeramicIntegration = new Integration("https://ceramic-clay.3boxlabs.com", "ethereum")` 46 | 4. Start the Lit Client when the DOM is loaded, or early on in the lifecycle: 47 | `litCeramicIntegration.startLitClient(window)` 48 | 5. You'll need to define access control conditions for your data. This will govern who is able to decrypt and therefore read the data. The access control conditions variable should be an array of conditions and the user must satisify all of them (a boolean "AND" operation) to access the data. You can find examples of conditions here: https://developer.litprotocol.com/docs/SDK/accessControlConditionExamples 49 | 50 | For example, this access control condition lets anyone who holds an NFT in the collection at 0x319ba3aab86e04a37053e984bd411b2c63bf229e on Ethereum to decrypt and read the data: 51 | 52 | ``` 53 | const accessControlConditions = [ 54 | { 55 | contractAddress: '0x319ba3aab86e04a37053e984bd411b2c63bf229e', 56 | standardContractType: 'ERC721', 57 | chain, 58 | method: 'balanceOf', 59 | parameters: [ 60 | ':userAddress' 61 | ], 62 | returnValueTest: { 63 | comparator: '>', 64 | value: '0' 65 | } 66 | } 67 | ] 68 | ``` 69 | 70 | 6. Use encryptAndWrite to encrypt and write your data to Ceramic: 71 | 72 | ``` 73 | const stringToEncrypt = 'This is what we want to encrypt on Lit and then store on ceramic' 74 | const response = litCeramicIntegration 75 | .encryptAndWrite(stringToEncrypt, accessControlConditions) 76 | .then((streamID) => console.log(streamID)) 77 | ``` 78 | 79 | Note that the stringToEncrypt is the thing which we are encrypting in this example, which could be any string (including JSON). The encryptAndWrite function returns a promise that contains the ceramic streamID of the content that was written. Note that you do need to save the streamID somewhere in order to retrieve the data later on. You could use localStorage or a database, but you'll need to save the streamID somewhere. 80 | 81 | 7. Use readAndDecrypt to read your data from ceramic and automatically decrypt it: 82 | 83 | ``` 84 | const streamID = 'kjzl6cwe1jw1479rnblkk5u43ivxkuo29i4efdx1e7hk94qrhjl0d4u0dyys1au' 85 | const response = litCeramicIntegration.readAndDecrypt(streamID).then( 86 | (value) => 87 | console.log(value) 88 | ) 89 | ``` 90 | 91 | This uses an example streamID and prints the secret value to the console. 92 | 93 | ## EVM Contract Conditions 94 | 95 | If you're using EVM Contract conditions instead of access control conditions, make sure you pass the optional 3rd parameter to encryptAndWrite of 'evmContractConditions': 96 | 97 | ``` 98 | const stringToEncrypt = 'This is what we want to encrypt on Lit and then store on ceramic' 99 | const response = litCeramicIntegration 100 | .encryptAndWrite(stringToEncrypt, evmContractConditions, 'evmContractConditions') 101 | .then((streamID) => console.log(streamID)) 102 | ``` 103 | 104 | ## API Docs 105 | 106 | You can find API docs [here](documentation/integration.md) 107 | 108 | ## Example 109 | 110 | You can find an example implementation here: https://github.com/LIT-Protocol/CeramicIntegrationExample 111 | 112 | ## More info 113 | 114 | Want to do something more complex with the Lit Protocol or Ceramic? Check out the Lit JS SDK docs https://developer.litprotocol.com/docs/SDK/intro and the Ceramic docs https://developers.ceramic.network/learn/welcome/ 115 | 116 | ### To Do / Desired Future Features 117 | 118 | - Change infuraID in ./wallet's `web3Modal`. 119 | - Enable Swap to Ceramic's mainnet 120 | 121 | ### Test Data 122 | 123 | #### Testing Ceramic Read Function 124 | 125 | If you'd like ping the ceramic test net for a streamID that already works, use the following streamID: `kjzl6cwe1jw14afliaj4m2vku3uy67ulyxj0erv5jgqz6k6cw0vtz27mf76m4ww` 126 | 127 | Manually, you can start the `ceramic daemon` and then in another terminal window enter `ceramic show kjzl6cwe1jw14afliaj4m2vku3uy67ulyxj0erv5jgqz6k6cw0vtz27mf76m4ww` 128 | It should return the following: 129 | 130 | ``` 131 | { 132 | "chain": "ethereum", 133 | "symKey": "gvKsVkBRS7d+baui7nJgf3b/G+8df1KNEYhVZ6kF97H8I0NROsKPd7BXds4jWbMK+rqlDa3Y2st4XQIHLqXLZVWJn5EZLNsYgEuZZPFaNbw7CGswjdSeMUK6WF8vAXS1+LbYrbal3GbTA+1JZ7Rc/xCKmpqM2Dvz2Btj8dhY3AUAAAAAAAAAIKnDOtW9nceKILkczbD1YjUyC3on3kTXKSJNyq2y4dmxy42BUuU6z+iI4WWZ2wmUhg==", 134 | "encryptedZip": "rAf1RDm7nf4STWdhPS4gYWrlNHS9HcAUO/w0E86xcEC5zdLIF0TlGKVqeCowGNKtB8ecz/zxFp/8Ra+js4WOwK/yATFi5AxoCu2s5653rDZr9AjIQ8ii4pKeeRm+qEnL3bzXtmJT+5XiixTz5zgxhGgOccYMdDeOjJUKf6okOFBwVLCrUHyPd4MdbE+SLA8/hnUh7EnTLykF+3GJnD0cyQ==", 135 | "accessControlConditions": [{ 136 | "chain": "ethereum", 137 | "method": "eth_getBalance", 138 | "parameters": [ 139 | ":userAddress", 140 | "latest" 141 | ], 142 | "contractAddress": "0x20598860da775f63ae75e1cd2ce0d462b8cee4c7", 143 | "returnValueTest": { 144 | "value": "10000000000000", 145 | "comparator": ">=" 146 | }, 147 | "standardContractType": "" 148 | }] 149 | } 150 | ``` 151 | 152 | ## Dependency Notes 153 | 154 | This project depends on https://www.npmjs.com/package/node-web-streams which has a dependency on a project from github via SSH. This means this package may not work on machines without SSH. 155 | -------------------------------------------------------------------------------- /dist/ceramic.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __assign = (this && this.__assign) || function () { 3 | __assign = Object.assign || function(t) { 4 | for (var s, i = 1, n = arguments.length; i < n; i++) { 5 | s = arguments[i]; 6 | for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) 7 | t[p] = s[p]; 8 | } 9 | return t; 10 | }; 11 | return __assign.apply(this, arguments); 12 | }; 13 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 14 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 15 | return new (P || (P = Promise))(function (resolve, reject) { 16 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 17 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 18 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 19 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 20 | }); 21 | }; 22 | var __generator = (this && this.__generator) || function (thisArg, body) { 23 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 24 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 25 | function verb(n) { return function (v) { return step([n, v]); }; } 26 | function step(op) { 27 | if (f) throw new TypeError("Generator is already executing."); 28 | while (_) try { 29 | if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; 30 | if (y = 0, t) op = [op[0] & 2, t.value]; 31 | switch (op[0]) { 32 | case 0: case 1: t = op; break; 33 | case 4: _.label++; return { value: op[1], done: false }; 34 | case 5: _.label++; y = op[1]; op = [0]; continue; 35 | case 7: op = _.ops.pop(); _.trys.pop(); continue; 36 | default: 37 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 38 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 39 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 40 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 41 | if (t[2]) _.ops.pop(); 42 | _.trys.pop(); continue; 43 | } 44 | op = body.call(thisArg, _); 45 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 46 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; 47 | } 48 | }; 49 | var __importDefault = (this && this.__importDefault) || function (mod) { 50 | return (mod && mod.__esModule) ? mod : { "default": mod }; 51 | }; 52 | Object.defineProperty(exports, "__esModule", { value: true }); 53 | exports._decodeFromB64 = exports._readCeramic = exports._updateCeramic = exports._writeCeramic = exports._authenticateCeramic = exports._createCeramic = void 0; 54 | var http_client_1 = __importDefault(require("@ceramicnetwork/http-client")); 55 | var stream_caip10_link_1 = require("@ceramicnetwork/stream-caip10-link"); 56 | var stream_tile_1 = require("@ceramicnetwork/stream-tile"); 57 | var dids_1 = require("dids"); 58 | var _3id_did_resolver_1 = __importDefault(require("@ceramicnetwork/3id-did-resolver")); 59 | var key_did_resolver_1 = __importDefault(require("key-did-resolver")); 60 | var idx_1 = require("./idx"); 61 | var wallet_1 = require("./wallet"); 62 | var lit_1 = require("./lit"); 63 | /** 64 | * Authenticate for Lit + Ceramic. 65 | * Creates a CeramicApi object on the ceramic testnet 66 | * 67 | * @returns {Promise} ceramicPromise pass in _createCeramic() promise 68 | */ 69 | function _createCeramic(ceramicNodeUrl) { 70 | return __awaiter(this, void 0, void 0, function () { 71 | var ceramic; 72 | return __generator(this, function (_a) { 73 | ceramic = new http_client_1.default(ceramicNodeUrl); 74 | window.ceramic = ceramic; 75 | window.TileDocument = stream_tile_1.TileDocument; 76 | window.Caip10Link = stream_caip10_link_1.Caip10Link; 77 | return [2 /*return*/, Promise.resolve(ceramic)]; 78 | }); 79 | }); 80 | } 81 | exports._createCeramic = _createCeramic; 82 | /** 83 | * Authenticate for Lit + Ceramic. 84 | * This uses a wallet provider to interact with the user's wallet 85 | * Once the user has authorized, the address is retrieved and the 86 | * decentralized identity is created. An IDX is also created for 87 | * convenience. 88 | * 89 | * @param {Promise} ceramicPromise pass in _createCeramic() promise 90 | * @returns {Promise>} Promise of ceramic IDX ID, ceramic object 91 | * and user's ETH Address 92 | */ 93 | function _authenticateCeramic(ceramicPromise) { 94 | return __awaiter(this, void 0, void 0, function () { 95 | var provider, _a, ceramic, address, keyDidResolver, threeIdResolver, resolverRegistry, did, idx; 96 | return __generator(this, function (_b) { 97 | switch (_b.label) { 98 | case 0: 99 | console.log("authenticate Ceramic!"); 100 | return [4 /*yield*/, (0, wallet_1.getProvider)()]; 101 | case 1: 102 | provider = _b.sent(); 103 | return [4 /*yield*/, Promise.all([ceramicPromise, (0, wallet_1.getAddress)()])]; 104 | case 2: 105 | _a = _b.sent(), ceramic = _a[0], address = _a[1]; 106 | keyDidResolver = key_did_resolver_1.default.getResolver(); 107 | threeIdResolver = _3id_did_resolver_1.default.getResolver(ceramic); 108 | resolverRegistry = __assign(__assign({}, threeIdResolver), keyDidResolver); 109 | did = new dids_1.DID({ 110 | provider: provider, 111 | resolver: resolverRegistry, 112 | }); 113 | return [4 /*yield*/, did.authenticate()]; 114 | case 3: 115 | _b.sent(); 116 | return [4 /*yield*/, ceramic.setDID(did)]; 117 | case 4: 118 | _b.sent(); 119 | idx = (0, idx_1.createIDX)(ceramic); 120 | window.did = ceramic.did; 121 | return [2 /*return*/, Promise.resolve([idx.id, ceramic, address])]; 122 | } 123 | }); 124 | }); 125 | } 126 | exports._authenticateCeramic = _authenticateCeramic; 127 | /** 128 | * Write to Ceramic. This function takes in an auth and what one would 129 | * like written and then sends it to a ceramic node in the proper format 130 | * @param {any[]} auth is the authentication passed via the persons wallet 131 | * @param {any[]} array of encrypted key, symkey, accessControlConditions, and chain 132 | * @returns {Promise} promise with the ceramic streamID, can be used to look up data 133 | */ 134 | function _writeCeramic(auth, toBeWritten) { 135 | return __awaiter(this, void 0, void 0, function () { 136 | var ceramic, toStore, doc; 137 | return __generator(this, function (_a) { 138 | switch (_a.label) { 139 | case 0: 140 | if (!auth) return [3 /*break*/, 2]; 141 | ceramic = auth[1]; 142 | toStore = { 143 | encryptedZip: toBeWritten[0], 144 | symKey: toBeWritten[1], 145 | accessControlConditions: toBeWritten[2], 146 | chain: toBeWritten[3], 147 | accessControlConditionType: toBeWritten[4], 148 | }; 149 | return [4 /*yield*/, stream_tile_1.TileDocument.create(ceramic, toStore, { 150 | // controllers: [concatId], 151 | family: "doc family", 152 | })]; 153 | case 1: 154 | doc = _a.sent(); 155 | return [2 /*return*/, doc.id.toString()]; 156 | case 2: 157 | console.error("Failed to authenticate in ceramic WRITE"); 158 | return [2 /*return*/, "error"]; 159 | } 160 | }); 161 | }); 162 | } 163 | exports._writeCeramic = _writeCeramic; 164 | function _updateCeramic(auth, streamId, newContent) { 165 | return __awaiter(this, void 0, void 0, function () { 166 | var ceramic, toStore, doc; 167 | return __generator(this, function (_a) { 168 | switch (_a.label) { 169 | case 0: 170 | if (!auth) return [3 /*break*/, 3]; 171 | ceramic = auth[1]; 172 | toStore = { 173 | encryptedZip: (0, lit_1.encodeb64)(newContent[0]), 174 | symKey: (0, lit_1.encodeb64)(newContent[1]), 175 | accessControlConditions: newContent[2], 176 | chain: newContent[3], 177 | accessControlConditionType: newContent[4], 178 | }; 179 | return [4 /*yield*/, stream_tile_1.TileDocument.load(ceramic, streamId.valueOf())]; 180 | case 1: 181 | doc = _a.sent(); 182 | console.log("$$$kl - loaded previous ceramic data from StreamID: ", streamId.valueOf()); 183 | console.log("$$$kl - previous doc: ", doc); 184 | console.log("$$$kl - new access control conditions: ", newContent[1]); 185 | return [4 /*yield*/, doc.update(toStore)]; 186 | case 2: 187 | _a.sent(); 188 | console.log("$$$kl - new doc: ", doc); 189 | return [2 /*return*/, "updated access conditions stored in Ceramic"]; 190 | case 3: 191 | console.error("Failed to authenticate in ceramic WRITE"); 192 | return [2 /*return*/, "error"]; 193 | } 194 | }); 195 | }); 196 | } 197 | exports._updateCeramic = _updateCeramic; 198 | /** 199 | * Read to Ceramic. This function takes in an auth and the streamID of the desired data and then sends it to a ceramic node in the proper format getting back a promised string of whatever was stored 200 | * 201 | * @param {any[]} auth is the authentication passed via the user's wallet 202 | * @param {String} streamId ID hash of the stream 203 | * @returns {Promise} promise with the ceramic streamID's output 204 | */ 205 | function _readCeramic(auth, streamId) { 206 | return __awaiter(this, void 0, void 0, function () { 207 | var ceramic, stream; 208 | return __generator(this, function (_a) { 209 | switch (_a.label) { 210 | case 0: 211 | if (!auth) return [3 /*break*/, 2]; 212 | ceramic = auth[1]; 213 | return [4 /*yield*/, ceramic.loadStream(streamId)]; 214 | case 1: 215 | stream = _a.sent(); 216 | return [2 /*return*/, stream.content]; 217 | case 2: 218 | console.error("Failed to authenticate in ceramic READ"); 219 | return [2 /*return*/, "error"]; 220 | } 221 | }); 222 | }); 223 | } 224 | exports._readCeramic = _readCeramic; 225 | /** 226 | * Decode info from base64. Data is stored in base64 to make upload to ceramic 227 | * more seamless. This function decodes it so it can be decrypted with Lit in 228 | * the next step in the read and decrypt process 229 | * 230 | * @param {string} response response received from ceramic streamID 231 | * @returns {Promise} array of decrypted zip and symmetric key + AAC and chain 232 | */ 233 | function _decodeFromB64(response) { 234 | return __awaiter(this, void 0, void 0, function () { 235 | var enZip, deZip, enSym, deSym, accessControlConditions, chain, accessControlConditionType; 236 | return __generator(this, function (_a) { 237 | // data is encoded in base64, decode 238 | // const jason = JSON.stringify(response); 239 | try { 240 | enZip = response["encryptedZip"]; 241 | deZip = (0, lit_1.decodeb64)(enZip); 242 | enSym = response["symKey"]; 243 | deSym = (0, lit_1.decodeb64)(enSym); 244 | accessControlConditions = response["accessControlConditions"]; 245 | chain = response["chain"]; 246 | accessControlConditionType = response["accessControlConditionType"]; 247 | return [2 /*return*/, [ 248 | deZip, 249 | deSym, 250 | accessControlConditions, 251 | chain, 252 | accessControlConditionType, 253 | ]]; 254 | } 255 | catch (error) { 256 | return [2 /*return*/, "There was an error decrypting, is it possible you inputted the wrong streamID?"]; 257 | } 258 | return [2 /*return*/]; 259 | }); 260 | }); 261 | } 262 | exports._decodeFromB64 = _decodeFromB64; 263 | -------------------------------------------------------------------------------- /dist/client.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 5 | }) : (function(o, m, k, k2) { 6 | if (k2 === undefined) k2 = k; 7 | o[k2] = m[k]; 8 | })); 9 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 10 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 11 | }) : function(o, v) { 12 | o["default"] = v; 13 | }); 14 | var __importStar = (this && this.__importStar) || function (mod) { 15 | if (mod && mod.__esModule) return mod; 16 | var result = {}; 17 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 18 | __setModuleDefault(result, mod); 19 | return result; 20 | }; 21 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 22 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 23 | return new (P || (P = Promise))(function (resolve, reject) { 24 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 25 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 26 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 27 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 28 | }); 29 | }; 30 | var __generator = (this && this.__generator) || function (thisArg, body) { 31 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 32 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 33 | function verb(n) { return function (v) { return step([n, v]); }; } 34 | function step(op) { 35 | if (f) throw new TypeError("Generator is already executing."); 36 | while (_) try { 37 | if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; 38 | if (y = 0, t) op = [op[0] & 2, t.value]; 39 | switch (op[0]) { 40 | case 0: case 1: t = op; break; 41 | case 4: _.label++; return { value: op[1], done: false }; 42 | case 5: _.label++; y = op[1]; op = [0]; continue; 43 | case 7: op = _.ops.pop(); _.trys.pop(); continue; 44 | default: 45 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 46 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 47 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 48 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 49 | if (t[2]) _.ops.pop(); 50 | _.trys.pop(); continue; 51 | } 52 | op = body.call(thisArg, _); 53 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 54 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; 55 | } 56 | }; 57 | Object.defineProperty(exports, "__esModule", { value: true }); 58 | exports._startLitClient = void 0; 59 | var LitJsSdk = __importStar(require("lit-js-sdk")); 60 | /** 61 | * Starts Lit Client in background. should be run upon starting of project. 62 | * 63 | * @param {Window} window the window of the project, to which it attaches 64 | * a litNodeClient 65 | */ 66 | function _startLitClient(window) { 67 | return __awaiter(this, void 0, void 0, function () { 68 | var client; 69 | return __generator(this, function (_a) { 70 | console.log("Starting Lit Client..."); 71 | client = new LitJsSdk.LitNodeClient(); 72 | client.connect(); 73 | window.litNodeClient = client; 74 | return [2 /*return*/]; 75 | }); 76 | }); 77 | } 78 | exports._startLitClient = _startLitClient; 79 | -------------------------------------------------------------------------------- /dist/idx.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.createIDX = void 0; 4 | var idx_1 = require("@ceramicstudio/idx"); 5 | function createIDX(ceramic) { 6 | var idx = new idx_1.IDX({ ceramic: ceramic }); 7 | window.idx = idx; 8 | return idx; 9 | } 10 | exports.createIDX = createIDX; 11 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // test code to start module 3 | Object.defineProperty(exports, "__esModule", { value: true }); 4 | exports.Integration = void 0; 5 | var integration_1 = require("./integration"); 6 | Object.defineProperty(exports, "Integration", { enumerable: true, get: function () { return integration_1.Integration; } }); 7 | -------------------------------------------------------------------------------- /dist/integration.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | var __generator = (this && this.__generator) || function (thisArg, body) { 12 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 13 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 14 | function verb(n) { return function (v) { return step([n, v]); }; } 15 | function step(op) { 16 | if (f) throw new TypeError("Generator is already executing."); 17 | while (_) try { 18 | if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; 19 | if (y = 0, t) op = [op[0] & 2, t.value]; 20 | switch (op[0]) { 21 | case 0: case 1: t = op; break; 22 | case 4: _.label++; return { value: op[1], done: false }; 23 | case 5: _.label++; y = op[1]; op = [0]; continue; 24 | case 7: op = _.ops.pop(); _.trys.pop(); continue; 25 | default: 26 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 27 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 28 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 29 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 30 | if (t[2]) _.ops.pop(); 31 | _.trys.pop(); continue; 32 | } 33 | op = body.call(thisArg, _); 34 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 35 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; 36 | } 37 | }; 38 | Object.defineProperty(exports, "__esModule", { value: true }); 39 | exports.Integration = void 0; 40 | var lit_1 = require("./lit"); 41 | var client_1 = require("./client"); 42 | var ceramic_1 = require("./ceramic"); 43 | var Integration = /** @class */ (function () { 44 | function Integration(ceramicNodeUrl, chainParam) { 45 | if (ceramicNodeUrl === void 0) { ceramicNodeUrl = "https://ceramic-clay.3boxlabs.com"; } 46 | if (chainParam === void 0) { chainParam = "ethereum"; } 47 | this.chain = chainParam; 48 | // console.log("setting chain to ", this.chain); 49 | this.ceramicPromise = (0, ceramic_1._createCeramic)(ceramicNodeUrl); 50 | } 51 | Integration.prototype.startLitClient = function (window) { 52 | (0, client_1._startLitClient)(window); 53 | }; 54 | /** 55 | * Encrypts using Lit and then writes using Ceramic 56 | * whatever the module user inputs (as long as it is a string for now) 57 | * 58 | * @param {String} toEncrypt what the module user wants to encrypt and store on ceramic 59 | * @param {Array} accessControlConditions the access control conditions that govern who is able to decrypt this data. See the docs here for examples: https://developer.litprotocol.com/docs/SDK/accessControlConditionExamples 60 | * @param {String} accessControlConditionType the access control condition type you are using. Pass `accessControlConditions` for traditional access control conditions. This is the default if you don't pass anything. Pass `evmContractConditions` for custom smart contract access control conditions 61 | * @returns {Promise} A promise that resolves to a streamID for the encrypted data that's been stored 62 | */ 63 | Integration.prototype.encryptAndWrite = function (toEncrypt, accessControlConditions, accessControlConditionType) { 64 | if (accessControlConditionType === void 0) { accessControlConditionType = "accessControlConditions"; } 65 | return __awaiter(this, void 0, void 0, function () { 66 | var a, en, wr, error_1; 67 | return __generator(this, function (_a) { 68 | switch (_a.label) { 69 | case 0: 70 | if (accessControlConditionType !== "accessControlConditions" && 71 | accessControlConditionType !== "evmContractConditions") { 72 | throw new Error("accessControlConditionType must be accessControlConditions or evmContractConditions"); 73 | } 74 | _a.label = 1; 75 | case 1: 76 | _a.trys.push([1, 5, , 6]); 77 | return [4 /*yield*/, (0, ceramic_1._authenticateCeramic)(this.ceramicPromise)]; 78 | case 2: 79 | a = _a.sent(); 80 | return [4 /*yield*/, (0, lit_1._encryptWithLit)(toEncrypt, accessControlConditions, this.chain, accessControlConditionType)]; 81 | case 3: 82 | en = _a.sent(); 83 | return [4 /*yield*/, (0, ceramic_1._writeCeramic)(a, en)]; 84 | case 4: 85 | wr = _a.sent(); 86 | return [2 /*return*/, wr]; 87 | case 5: 88 | error_1 = _a.sent(); 89 | return [2 /*return*/, "something went wrong encrypting: ".concat(error_1)]; 90 | case 6: return [2 /*return*/]; 91 | } 92 | }); 93 | }); 94 | }; 95 | /** 96 | * Retrieves a stream and decrypts message then returns to user 97 | * 98 | * @param {String} streamID the streamID of the encrypted data the user wants to access 99 | * @returns {Promise} A promise that resolves to the unencrypted string of what was stored 100 | */ 101 | Integration.prototype.readAndDecrypt = function (streamID) { 102 | return __awaiter(this, void 0, void 0, function () { 103 | var a, en, deco, decrypt, error_2; 104 | return __generator(this, function (_a) { 105 | switch (_a.label) { 106 | case 0: 107 | _a.trys.push([0, 5, , 6]); 108 | return [4 /*yield*/, (0, ceramic_1._authenticateCeramic)(this.ceramicPromise)]; 109 | case 1: 110 | a = _a.sent(); 111 | console.log("authenticated RnD: ", a); 112 | return [4 /*yield*/, (0, ceramic_1._readCeramic)(a, streamID)]; 113 | case 2: 114 | en = _a.sent(); 115 | console.log("read from ceramic RnD: ", en); 116 | return [4 /*yield*/, (0, ceramic_1._decodeFromB64)(en)]; 117 | case 3: 118 | deco = _a.sent(); 119 | console.log("data from ceramic: ", deco); 120 | return [4 /*yield*/, (0, lit_1._decryptWithLit)(deco[0], deco[1], deco[2], deco[3], deco[4])]; 121 | case 4: 122 | decrypt = _a.sent(); 123 | return [2 /*return*/, decrypt]; 124 | case 5: 125 | error_2 = _a.sent(); 126 | console.log("something went wrong decrypting: ".concat(error_2, " \n StreamID sent: ").concat(streamID)); 127 | return [2 /*return*/, "FALSE"]; 128 | case 6: return [2 /*return*/]; 129 | } 130 | }); 131 | }); 132 | }; 133 | /** 134 | * Retrieves a stream and decrypts message then returns to user 135 | * 136 | * @param {String} streamID the streamID of the encrypted data that you want to update the access control conditions for 137 | * @param {Array} accessControlConditions the access control conditions that govern who is able to decrypt this data. Note that you cannot change the accessControlConditionType using this method, and you must use the same condition type that was used when you ran encryptAndWrite. See the docs here for examples of accessControlConditions: https://developer.litprotocol.com/docs/SDK/accessControlConditionExamples 138 | * @returns {Promise} A promise that resolves to the unencrypted string of what was stored 139 | */ 140 | Integration.prototype.updateAccess = function (streamID, newAccessControlConditions) { 141 | return __awaiter(this, void 0, void 0, function () { 142 | var a, en, deco, result, newContent, result2, error_3; 143 | return __generator(this, function (_a) { 144 | switch (_a.label) { 145 | case 0: 146 | _a.trys.push([0, 6, , 7]); 147 | console.log("trying to update permissions for streamID: ", streamID); 148 | return [4 /*yield*/, (0, ceramic_1._authenticateCeramic)(this.ceramicPromise)]; 149 | case 1: 150 | a = _a.sent(); 151 | console.log("authenticated: ", a); 152 | return [4 /*yield*/, (0, ceramic_1._readCeramic)(a, streamID)]; 153 | case 2: 154 | en = _a.sent(); 155 | console.log("read from ceramic: ", en); 156 | return [4 /*yield*/, (0, ceramic_1._decodeFromB64)(en)]; 157 | case 3: 158 | deco = _a.sent(); 159 | console.log("data from ceramic: ", deco); 160 | return [4 /*yield*/, (0, lit_1._saveEncryptionKey)(newAccessControlConditions, deco[1], //encryptedSymmetricKey 161 | this.chain)]; 162 | case 4: 163 | result = _a.sent(); 164 | console.log("update access result: ", result); 165 | newContent = [ 166 | deco[0], 167 | deco[1], 168 | newAccessControlConditions, 169 | deco[3], 170 | deco[4], 171 | ]; 172 | //save the access conditions back to Ceramic 173 | console.log("saving new ceramic access conditions: ", newContent, newAccessControlConditions); 174 | return [4 /*yield*/, (0, ceramic_1._updateCeramic)(a, streamID, newContent)]; 175 | case 5: 176 | result2 = _a.sent(); 177 | console.log("update ceramic access conditions: ", streamID, result); 178 | return [2 /*return*/, result2]; 179 | case 6: 180 | error_3 = _a.sent(); 181 | return [2 /*return*/, "something went wrong encrypting: ".concat(error_3)]; 182 | case 7: return [2 /*return*/]; 183 | } 184 | }); 185 | }); 186 | }; 187 | return Integration; 188 | }()); 189 | exports.Integration = Integration; 190 | -------------------------------------------------------------------------------- /dist/lit.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { 3 | if (k2 === undefined) k2 = k; 4 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); 5 | }) : (function(o, m, k, k2) { 6 | if (k2 === undefined) k2 = k; 7 | o[k2] = m[k]; 8 | })); 9 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { 10 | Object.defineProperty(o, "default", { enumerable: true, value: v }); 11 | }) : function(o, v) { 12 | o["default"] = v; 13 | }); 14 | var __importStar = (this && this.__importStar) || function (mod) { 15 | if (mod && mod.__esModule) return mod; 16 | var result = {}; 17 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); 18 | __setModuleDefault(result, mod); 19 | return result; 20 | }; 21 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 22 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 23 | return new (P || (P = Promise))(function (resolve, reject) { 24 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 25 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 26 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 27 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 28 | }); 29 | }; 30 | var __generator = (this && this.__generator) || function (thisArg, body) { 31 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 32 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 33 | function verb(n) { return function (v) { return step([n, v]); }; } 34 | function step(op) { 35 | if (f) throw new TypeError("Generator is already executing."); 36 | while (_) try { 37 | if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; 38 | if (y = 0, t) op = [op[0] & 2, t.value]; 39 | switch (op[0]) { 40 | case 0: case 1: t = op; break; 41 | case 4: _.label++; return { value: op[1], done: false }; 42 | case 5: _.label++; y = op[1]; op = [0]; continue; 43 | case 7: op = _.ops.pop(); _.trys.pop(); continue; 44 | default: 45 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 46 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 47 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 48 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 49 | if (t[2]) _.ops.pop(); 50 | _.trys.pop(); continue; 51 | } 52 | op = body.call(thisArg, _); 53 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 54 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; 55 | } 56 | }; 57 | Object.defineProperty(exports, "__esModule", { value: true }); 58 | exports._saveEncryptionKey = exports._decryptWithLit = exports._encryptWithLit = exports.decodeb64 = exports.blobToBase64 = exports.encodeb64 = void 0; 59 | // import LitJsSdk from 'lit-js-sdk' 60 | var LitJsSdk = __importStar(require("lit-js-sdk")); 61 | var to_string_1 = require("uint8arrays/to-string"); 62 | /** 63 | * This function encodes into base 64. 64 | * it's useful for storing symkeys and files in ceramic 65 | * @param {Uint8Array} input a file or any data 66 | * @returns {string} returns a string of b64 67 | */ 68 | function encodeb64(uintarray) { 69 | var b64 = Buffer.from(uintarray).toString("base64"); 70 | return b64; 71 | } 72 | exports.encodeb64 = encodeb64; 73 | /** 74 | * This function converts blobs to base 64. 75 | * for easier storage in ceramic 76 | * @param {Blob} blob what you'd like to encode 77 | * @returns {Promise} returns a string of b64 78 | */ 79 | function blobToBase64(blob) { 80 | return new Promise(function (resolve, _) { 81 | var reader = new FileReader(); 82 | reader.onloadend = function () { 83 | return resolve( 84 | // @ts-ignore 85 | reader.result.replace("data:application/octet-stream;base64,", "")); 86 | }; 87 | reader.readAsDataURL(blob); 88 | }); 89 | } 90 | exports.blobToBase64 = blobToBase64; 91 | /** 92 | * This function decodes from base 64. 93 | * it's useful for decrypting symkeys and files in ceramic 94 | * @param {blob} input a b64 string 95 | * @returns {string} returns the data as a string 96 | */ 97 | function decodeb64(b64String) { 98 | return new Uint8Array(Buffer.from(b64String, "base64")); 99 | } 100 | exports.decodeb64 = decodeb64; 101 | /** 102 | * encrypts a message with Lit returns required details 103 | * this obfuscates data such that it can be stored on ceramic without 104 | * non-permissioned eyes seeing what the data is 105 | * @param {String} aStringThatYouWishToEncrypt the clear text you'd like encrypted 106 | * @param {Array} accessControlConditions the access control conditions that govern who is able to decrypt this data. See the docs here for examples: https://developer.litprotocol.com/docs/SDK/accessControlConditionExamples 107 | * @param {String} chain the chain you'd like to use for checking the access control conditions 108 | * @param {String} accessControlConditionType the access control condition type you are using. Pass `accessControlConditions` for traditional access control conditions. This is the default if you don't pass anything. Pass `evmContractConditions` for custom smart contract access control conditions 109 | * @returns {Promise>} returns, in this order: encryptedZipBase64, encryptedSymmetricKeyBase64, accessControlConditions, chain 110 | */ 111 | function _encryptWithLit(aStringThatYouWishToEncrypt, accessControlConditions, chain, accessControlConditionType) { 112 | if (accessControlConditionType === void 0) { accessControlConditionType = "accessControlConditions"; } 113 | return __awaiter(this, void 0, void 0, function () { 114 | var authSig, _a, encryptedZip, symmetricKey, encryptedSymmetricKey, encryptedZipBase64, encryptedSymmetricKeyBase64; 115 | return __generator(this, function (_b) { 116 | switch (_b.label) { 117 | case 0: return [4 /*yield*/, LitJsSdk.checkAndSignAuthMessage({ 118 | chain: chain, 119 | })]; 120 | case 1: 121 | authSig = _b.sent(); 122 | return [4 /*yield*/, LitJsSdk.zipAndEncryptString(aStringThatYouWishToEncrypt)]; 123 | case 2: 124 | _a = _b.sent(), encryptedZip = _a.encryptedZip, symmetricKey = _a.symmetricKey; 125 | if (!(accessControlConditionType === "accessControlConditions")) return [3 /*break*/, 4]; 126 | return [4 /*yield*/, window.litNodeClient.saveEncryptionKey({ 127 | accessControlConditions: accessControlConditions, 128 | symmetricKey: symmetricKey, 129 | authSig: authSig, 130 | chain: chain, 131 | permanant: false, 132 | })]; 133 | case 3: 134 | encryptedSymmetricKey = _b.sent(); 135 | return [3 /*break*/, 7]; 136 | case 4: 137 | if (!(accessControlConditionType === "evmContractConditions")) return [3 /*break*/, 6]; 138 | return [4 /*yield*/, window.litNodeClient.saveEncryptionKey({ 139 | evmContractConditions: accessControlConditions, 140 | symmetricKey: symmetricKey, 141 | authSig: authSig, 142 | chain: chain, 143 | permanant: false, 144 | })]; 145 | case 5: 146 | encryptedSymmetricKey = _b.sent(); 147 | return [3 /*break*/, 7]; 148 | case 6: throw new Error("accessControlConditionType must be accessControlConditions or evmContractConditions"); 149 | case 7: return [4 /*yield*/, blobToBase64(encryptedZip)]; 150 | case 8: 151 | encryptedZipBase64 = _b.sent(); 152 | encryptedSymmetricKeyBase64 = encodeb64(encryptedSymmetricKey); 153 | return [2 /*return*/, [ 154 | encryptedZipBase64, 155 | encryptedSymmetricKeyBase64, 156 | accessControlConditions, 157 | chain, 158 | accessControlConditionType, 159 | ]]; 160 | } 161 | }); 162 | }); 163 | } 164 | exports._encryptWithLit = _encryptWithLit; 165 | /** 166 | * decrypt encrypted zip and symmetric key using the lit protocol 167 | * @param {Uint8Array} encryptedZip encrypted data that will be converted into a string 168 | * @param {Uint8Array} encryptedSymmKey symmetric key 169 | * @param {Array} accessControlConditions conditions that determine access 170 | * @param {String} chain the chain you'd like to use for checking the access control conditions 171 | * @param {String} accessControlConditionType the access control condition type you are using. Pass `accessControlConditions` for traditional access control conditions. This is the default if you don't pass anything. Pass `evmContractConditions` for custom smart contract access control conditions 172 | * @returns {Promise} promise with the decrypted string 173 | */ 174 | function _decryptWithLit(encryptedZip, encryptedSymmKey, accessControlConditions, chain, accessControlConditionType) { 175 | if (accessControlConditionType === void 0) { accessControlConditionType = "accessControlConditions"; } 176 | return __awaiter(this, void 0, void 0, function () { 177 | var authSig, toDecrypt, decryptedSymmKey, decryptedFiles, decryptedString; 178 | return __generator(this, function (_a) { 179 | switch (_a.label) { 180 | case 0: return [4 /*yield*/, LitJsSdk.checkAndSignAuthMessage({ 181 | chain: chain, 182 | })]; 183 | case 1: 184 | authSig = _a.sent(); 185 | // encrypted blob, sym key 186 | console.log("encryptedSymKey", encryptedSymmKey); 187 | toDecrypt = (0, to_string_1.toString)(encryptedSymmKey, "base16"); 188 | console.log("toDecrypt", toDecrypt); 189 | if (!(accessControlConditionType === "accessControlConditions")) return [3 /*break*/, 3]; 190 | return [4 /*yield*/, window.litNodeClient.getEncryptionKey({ 191 | accessControlConditions: accessControlConditions, 192 | toDecrypt: toDecrypt, 193 | chain: chain, 194 | authSig: authSig, 195 | })]; 196 | case 2: 197 | decryptedSymmKey = _a.sent(); 198 | return [3 /*break*/, 5]; 199 | case 3: 200 | if (!(accessControlConditionType === "evmContractConditions")) return [3 /*break*/, 5]; 201 | return [4 /*yield*/, window.litNodeClient.getEncryptionKey({ 202 | evmContractConditions: accessControlConditions, 203 | toDecrypt: toDecrypt, 204 | chain: chain, 205 | authSig: authSig, 206 | })]; 207 | case 4: 208 | decryptedSymmKey = _a.sent(); 209 | _a.label = 5; 210 | case 5: 211 | console.log("decryptedSymKey", decryptedSymmKey); 212 | return [4 /*yield*/, LitJsSdk.decryptZip(new Blob([encryptedZip]), decryptedSymmKey)]; 213 | case 6: 214 | decryptedFiles = _a.sent(); 215 | return [4 /*yield*/, decryptedFiles["string.txt"].async("text")]; 216 | case 7: 217 | decryptedString = _a.sent(); 218 | return [2 /*return*/, decryptedString]; 219 | } 220 | }); 221 | }); 222 | } 223 | exports._decryptWithLit = _decryptWithLit; 224 | // litCeramicIntegration.saveEncryptionKey({ 225 | // accessControlConditions: newAccessControlConditions, 226 | // encryptedSymmetricKey, 227 | // authSig, 228 | // chain, 229 | // permanant: false, 230 | // }); 231 | function _saveEncryptionKey(newAccessControlConditions, encryptedSymmetricKey, chain) { 232 | return __awaiter(this, void 0, void 0, function () { 233 | var authSig, newEncryptedSymmetricKey; 234 | return __generator(this, function (_a) { 235 | switch (_a.label) { 236 | case 0: return [4 /*yield*/, LitJsSdk.checkAndSignAuthMessage({ 237 | chain: chain, 238 | })]; 239 | case 1: 240 | authSig = _a.sent(); 241 | return [4 /*yield*/, window.litNodeClient.saveEncryptionKey({ 242 | accessControlConditions: newAccessControlConditions, 243 | encryptedSymmetricKey: encryptedSymmetricKey, 244 | authSig: authSig, 245 | chain: chain, 246 | permanant: false, 247 | })]; 248 | case 2: 249 | newEncryptedSymmetricKey = _a.sent(); 250 | console.log("updated the access control condition"); 251 | return [2 /*return*/, newEncryptedSymmetricKey]; 252 | } 253 | }); 254 | }); 255 | } 256 | exports._saveEncryptionKey = _saveEncryptionKey; 257 | -------------------------------------------------------------------------------- /dist/wallet.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { 3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } 4 | return new (P || (P = Promise))(function (resolve, reject) { 5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } 8 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 9 | }); 10 | }; 11 | var __generator = (this && this.__generator) || function (thisArg, body) { 12 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 13 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 14 | function verb(n) { return function (v) { return step([n, v]); }; } 15 | function step(op) { 16 | if (f) throw new TypeError("Generator is already executing."); 17 | while (_) try { 18 | if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; 19 | if (y = 0, t) op = [op[0] & 2, t.value]; 20 | switch (op[0]) { 21 | case 0: case 1: t = op; break; 22 | case 4: _.label++; return { value: op[1], done: false }; 23 | case 5: _.label++; y = op[1]; op = [0]; continue; 24 | case 7: op = _.ops.pop(); _.trys.pop(); continue; 25 | default: 26 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 27 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 28 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 29 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 30 | if (t[2]) _.ops.pop(); 31 | _.trys.pop(); continue; 32 | } 33 | op = body.call(thisArg, _); 34 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 35 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; 36 | } 37 | }; 38 | var __importDefault = (this && this.__importDefault) || function (mod) { 39 | return (mod && mod.__esModule) ? mod : { "default": mod }; 40 | }; 41 | Object.defineProperty(exports, "__esModule", { value: true }); 42 | exports.getAddress = exports.getProvider = exports.threeID = void 0; 43 | var connect_1 = require("@3id/connect"); 44 | var lit_js_sdk_1 = __importDefault(require("lit-js-sdk")); 45 | // @ts-ignore 46 | exports.threeID = new connect_1.ThreeIdConnect(); 47 | function getProvider() { 48 | return __awaiter(this, void 0, void 0, function () { 49 | var _a, web3, account; 50 | return __generator(this, function (_b) { 51 | switch (_b.label) { 52 | case 0: return [4 /*yield*/, lit_js_sdk_1.default.connectWeb3()]; 53 | case 1: 54 | _a = _b.sent(), web3 = _a.web3, account = _a.account; 55 | return [4 /*yield*/, exports.threeID.connect(new connect_1.EthereumAuthProvider(web3.provider, account))]; 56 | case 2: 57 | _b.sent(); 58 | return [2 /*return*/, exports.threeID.getDidProvider()]; 59 | } 60 | }); 61 | }); 62 | } 63 | exports.getProvider = getProvider; 64 | function getAddress() { 65 | return __awaiter(this, void 0, void 0, function () { 66 | var _a, web3, account; 67 | return __generator(this, function (_b) { 68 | switch (_b.label) { 69 | case 0: return [4 /*yield*/, lit_js_sdk_1.default.connectWeb3()]; 70 | case 1: 71 | _a = _b.sent(), web3 = _a.web3, account = _a.account; 72 | return [2 /*return*/, account]; 73 | } 74 | }); 75 | }); 76 | } 77 | exports.getAddress = getAddress; 78 | -------------------------------------------------------------------------------- /documentation/_howToUpdateDocs.md: -------------------------------------------------------------------------------- 1 | # How To Update Documentation 2 | 3 | ###### Skip to the end if you want.. 4 | 5 | DocumentationJS 'works' with Typescript... But not particularly well. As such the way to update the docs is a little wonky, and you have to run through them TS file by TS file. 6 | 7 | As such, here are the files that have documentation and the commands that should be run. 8 | 9 | `documentation build integration.ts --parse-extension ts -f md -o documentation/integration --shallow` 10 | `documentation build lit.ts --parse-extension ts -f md -o documentation/lit --shallow` 11 | `documentation build ceramic.ts --parse-extension ts -f md -o documentation/ceramic --shallow` 12 | `documentation build client.ts --parse-extension ts -f md -o documentation/client --shallow` 13 | 14 | ### But wait, there's more!!!! 15 | 16 | There's a convenience script that has been made to do all of these at once: 17 | `yarn build:docs` 18 | -------------------------------------------------------------------------------- /documentation/ceramic.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [\_createCeramic][1] 6 | * [Parameters][2] 7 | * [\_authenticateCeramic][3] 8 | * [Parameters][4] 9 | * [\_writeCeramic][5] 10 | * [Parameters][6] 11 | * [\_readCeramic][7] 12 | * [Parameters][8] 13 | * [\_decodeFromB64][9] 14 | * [Parameters][10] 15 | 16 | ## \_createCeramic 17 | 18 | Authenticate for Lit + Ceramic. 19 | Creates a CeramicApi object on the ceramic testnet 20 | 21 | ### Parameters 22 | 23 | * `ceramicNodeUrl` **[string][11]** 24 | 25 | Returns **[Promise][12]\** ceramicPromise pass in \_createCeramic() promise 26 | 27 | ## \_authenticateCeramic 28 | 29 | Authenticate for Lit + Ceramic. 30 | This uses a wallet provider to interact with the user's wallet 31 | Once the user has authorized, the address is retrieved and the 32 | decentralized identity is created. An IDX is also created for 33 | convenience. 34 | 35 | ### Parameters 36 | 37 | * `ceramicPromise` **[Promise][12]\** pass in \_createCeramic() promise 38 | 39 | Returns **[Promise][12]<[Array][13]\>** Promise of ceramic IDX ID, ceramic object 40 | and user's ETH Address 41 | 42 | ## \_writeCeramic 43 | 44 | Write to Ceramic. This function takes in an auth and what one would 45 | like written and then sends it to a ceramic node in the proper format 46 | 47 | ### Parameters 48 | 49 | * `auth` **[Array][13]\** is the authentication passed via the persons wallet 50 | * `toBeWritten` **[Array][13]\** 51 | * `array` **[Array][13]\** of encrypted key, symkey, accessControlConditions, and chain 52 | 53 | Returns **[Promise][12]<[string][11]>** promise with the ceramic streamID, can be used to look up data 54 | 55 | ## \_readCeramic 56 | 57 | Read to Ceramic. This function takes in an auth and the streamID of the desired data and then sends it to a ceramic node in the proper format getting back a promised string of whatever was stored 58 | 59 | ### Parameters 60 | 61 | * `auth` **[Array][13]\** is the authentication passed via the user's wallet 62 | * `streamId` **[String][11]** ID hash of the stream 63 | 64 | Returns **[Promise][12]<[string][11]>** promise with the ceramic streamID's output 65 | 66 | ## \_decodeFromB64 67 | 68 | Decode info from base64. Data is stored in base64 to make upload to ceramic 69 | more seamless. This function decodes it so it can be decrypted with Lit in 70 | the next step in the read and decrypt process 71 | 72 | ### Parameters 73 | 74 | * `response` **[string][11]** response received from ceramic streamID 75 | 76 | [1]: #_createceramic 77 | 78 | [2]: #parameters 79 | 80 | [3]: #_authenticateceramic 81 | 82 | [4]: #parameters-1 83 | 84 | [5]: #_writeceramic 85 | 86 | [6]: #parameters-2 87 | 88 | [7]: #_readceramic 89 | 90 | [8]: #parameters-3 91 | 92 | [9]: #_decodefromb64 93 | 94 | [10]: #parameters-4 95 | 96 | [11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 97 | 98 | [12]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise 99 | 100 | [13]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 101 | -------------------------------------------------------------------------------- /documentation/client.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [\_startLitClient][1] 6 | * [Parameters][2] 7 | 8 | ## \_startLitClient 9 | 10 | Starts Lit Client in background. should be run upon starting of project. 11 | 12 | ### Parameters 13 | 14 | * `window` **[Window][3]** the window of the project, to which it attaches 15 | a litNodeClient 16 | 17 | [1]: #_startlitclient 18 | 19 | [2]: #parameters 20 | 21 | [3]: https://developer.mozilla.org/docs/Web/API/Window 22 | -------------------------------------------------------------------------------- /documentation/integration.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [encryptAndWrite][1] 6 | * [Parameters][2] 7 | * [readAndDecrypt][3] 8 | * [Parameters][4] 9 | * [updateAccess][5] 10 | * [Parameters][6] 11 | 12 | ## encryptAndWrite 13 | 14 | Encrypts using Lit and then writes using Ceramic 15 | whatever the module user inputs (as long as it is a string for now) 16 | 17 | ### Parameters 18 | 19 | * `toEncrypt` **[String][7]** what the module user wants to encrypt and store on ceramic 20 | * `accessControlConditions` **[Array][8]<[Object][9]>** the access control conditions that govern who is able to decrypt this data. See the docs here for examples: [https://developer.litprotocol.com/docs/SDK/accessControlConditionExamples][10] 21 | * `accessControlConditionType` **[String][7]** the access control condition type you are using. Pass `accessControlConditions` for traditional access control conditions. This is the default if you don't pass anything. Pass `evmContractConditions` for custom smart contract access control conditions (optional, default `"accessControlConditions"`) 22 | 23 | Returns **[Promise][11]<[String][7]>** A promise that resolves to a streamID for the encrypted data that's been stored 24 | 25 | ## readAndDecrypt 26 | 27 | Retrieves a stream and decrypts message then returns to user 28 | 29 | ### Parameters 30 | 31 | * `streamID` **[String][7]** the streamID of the encrypted data the user wants to access 32 | 33 | Returns **[Promise][11]<[String][7]>** A promise that resolves to the unencrypted string of what was stored 34 | 35 | ## updateAccess 36 | 37 | Retrieves a stream and decrypts message then returns to user 38 | 39 | ### Parameters 40 | 41 | * `streamID` **[String][7]** the streamID of the encrypted data that you want to update the access control conditions for 42 | * `newAccessControlConditions` **[Array][8]<[Object][9]>** 43 | * `accessControlConditions` **[Array][8]<[Object][9]>** the access control conditions that govern who is able to decrypt this data. Note that you cannot change the accessControlConditionType using this method, and you must use the same condition type that was used when you ran encryptAndWrite. See the docs here for examples of accessControlConditions: [https://developer.litprotocol.com/docs/SDK/accessControlConditionExamples][10] 44 | 45 | Returns **[Promise][11]<[String][7]>** A promise that resolves to the unencrypted string of what was stored 46 | 47 | [1]: #encryptandwrite 48 | 49 | [2]: #parameters 50 | 51 | [3]: #readanddecrypt 52 | 53 | [4]: #parameters-1 54 | 55 | [5]: #updateaccess 56 | 57 | [6]: #parameters-2 58 | 59 | [7]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 60 | 61 | [8]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 62 | 63 | [9]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object 64 | 65 | [10]: https://developer.litprotocol.com/docs/SDK/accessControlConditionExamples 66 | 67 | [11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise 68 | -------------------------------------------------------------------------------- /documentation/lit.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Table of Contents 4 | 5 | * [encodeb64][1] 6 | * [Parameters][2] 7 | * [blobToBase64][3] 8 | * [Parameters][4] 9 | * [decodeb64][5] 10 | * [Parameters][6] 11 | * [\_encryptWithLit][7] 12 | * [Parameters][8] 13 | * [\_decryptWithLit][9] 14 | * [Parameters][10] 15 | 16 | ## encodeb64 17 | 18 | This function encodes into base 64. 19 | it's useful for storing symkeys and files in ceramic 20 | 21 | ### Parameters 22 | 23 | * `uintarray` **any** 24 | * `input` **[Uint8Array][11]** a file or any data 25 | 26 | Returns **[string][12]** returns a string of b64 27 | 28 | ## blobToBase64 29 | 30 | This function converts blobs to base 64. 31 | for easier storage in ceramic 32 | 33 | ### Parameters 34 | 35 | * `blob` **[Blob][13]** what you'd like to encode 36 | 37 | Returns **[Promise][14]<[String][12]>** returns a string of b64 38 | 39 | ## decodeb64 40 | 41 | This function decodes from base 64. 42 | it's useful for decrypting symkeys and files in ceramic 43 | 44 | ### Parameters 45 | 46 | * `b64String` **any** 47 | * `input` **[blob][13]** a b64 string 48 | 49 | Returns **[string][12]** returns the data as a string 50 | 51 | ## \_encryptWithLit 52 | 53 | encrypts a message with Lit returns required details 54 | this obfuscates data such that it can be stored on ceramic without 55 | non-permissioned eyes seeing what the data is 56 | 57 | ### Parameters 58 | 59 | * `aStringThatYouWishToEncrypt` **[String][12]** the clear text you'd like encrypted 60 | * `accessControlConditions` **[Array][15]<[Object][16]>** the access control conditions that govern who is able to decrypt this data. See the docs here for examples: [https://developer.litprotocol.com/docs/SDK/accessControlConditionExamples][17] 61 | * `chain` **[String][12]** the chain you'd like to use for checking the access control conditions 62 | * `accessControlConditionType` **[String][12]** the access control condition type you are using. Pass `accessControlConditions` for traditional access control conditions. This is the default if you don't pass anything. Pass `evmContractConditions` for custom smart contract access control conditions (optional, default `"accessControlConditions"`) 63 | 64 | Returns **[Promise][14]<[Array][15]\>** returns, in this order: encryptedZipBase64, encryptedSymmetricKeyBase64, accessControlConditions, chain 65 | 66 | ## \_decryptWithLit 67 | 68 | decrypt encrypted zip and symmetric key using the lit protocol 69 | 70 | ### Parameters 71 | 72 | * `encryptedZip` **[Uint8Array][11]** encrypted data that will be converted into a string 73 | * `encryptedSymmKey` **[Uint8Array][11]** symmetric key 74 | * `accessControlConditions` **[Array][15]\** conditions that determine access 75 | * `chain` **[String][12]** the chain you'd like to use for checking the access control conditions 76 | * `accessControlConditionType` **[String][12]** the access control condition type you are using. Pass `accessControlConditions` for traditional access control conditions. This is the default if you don't pass anything. Pass `evmContractConditions` for custom smart contract access control conditions (optional, default `"accessControlConditions"`) 77 | 78 | Returns **[Promise][14]<[string][12]>** promise with the decrypted string 79 | 80 | [1]: #encodeb64 81 | 82 | [2]: #parameters 83 | 84 | [3]: #blobtobase64 85 | 86 | [4]: #parameters-1 87 | 88 | [5]: #decodeb64 89 | 90 | [6]: #parameters-2 91 | 92 | [7]: #_encryptwithlit 93 | 94 | [8]: #parameters-3 95 | 96 | [9]: #_decryptwithlit 97 | 98 | [10]: #parameters-4 99 | 100 | [11]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array 101 | 102 | [12]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String 103 | 104 | [13]: https://developer.mozilla.org/docs/Web/API/Blob 105 | 106 | [14]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise 107 | 108 | [15]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array 109 | 110 | [16]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object 111 | 112 | [17]: https://developer.litprotocol.com/docs/SDK/accessControlConditionExamples 113 | -------------------------------------------------------------------------------- /notes.md: -------------------------------------------------------------------------------- 1 | # General Notes From Building with Ceramic 2 | 3 | ### Node 4 | 5 | For ceramic you're required to run a client, which can either be based on your own node (using their "core" client Implementation) or using their JS HTTP client. Core requires setting up a IPFS node and a dag-jose apparently, so for now if I need to do this, and it looks like I do, I'm going with JS HTTP. 6 | 7 | # Glossary 8 | 9 | I found it useful to define some things things in short form, full glossary can be [found here](https://developers.ceramic.network/learn/glossary/). Some phrases are direct copies, most aren't. 10 | 11 | ## DID 12 | 13 | ### DID - 14 | 15 | Decentralized Identifier, used to identify an entity, person, etc. via an agreed upon URI schema. They're used for Authentication by most StreamTypes 16 | 17 | ### DID Methods - 18 | 19 | Implementation of the DID specification. DID methods must specify: 20 | 21 | 1. A name for the method in the form of a string 22 | 2. A description of where the DID document is stored (or how it is statically generated) 23 | 3. A DID resolver which: --> 24 | 25 | - CAN return a DID document, 26 | - GIVEN a URI 27 | - WHICH conforms to that particular DID method. 28 | 29 | There's an official method registry for DID methods with over 40 of them (maintained by the W3C), so that's cool. 30 | 31 | For reference, and DID URI looks like this: 32 | `did::` 33 | 34 | ### DID Document - 35 | 36 | Contain metadata about a DID. Contains cryptographic key data for auth, at a minimium. 37 | 38 | ### DID Resolver - 39 | 40 | Must be imported upon installation of JS HTTP or Core Client 41 | 42 | ### DID Providers - 43 | 44 | DID providers are software libraries that expose a json-rpc interface which allows for the creation and usage of a DID that conforms to a particular DID method. 45 | 46 | Usually a DID provider is constructed using a seed that the user controls. When using Ceramic with streams that require DIDs for authentication, applications either need to integrate a DID provider library, which leaves the responsibility of key management up to the application, or a DID wallet, which is a more user-friendly experience. 47 | 48 | ### DID Wallets - 49 | 50 | DID wallets are software libraries or end-user applications that wrap DID providers with additional capabilities 51 | 52 | 3ID is the most popular wallet. 53 | 54 | ## Ceramic 55 | 56 | ### StreamType - 57 | 58 | The processing logic used by the particular stream. 59 | 60 | ### Tile Document - 61 | 62 | A StreamType that stores a JSON document, providing similar functionality as a NoSQL document store. 63 | 64 | used as a database replacement for identity metadata (profiles, social graphs, reputation scores, linked social accounts), user-generated content (blog posts, social media, etc), indexes of other StreamIDs to form collections and user tables (IDX), DID documents, verifiable claims, and more 65 | 66 | ### CAIP-10 Link - 67 | 68 | A StreamType that stores a cryptographically verifiable proof that links a blockchain address to a DID. 69 | 70 | # Useful Links 71 | 72 | Lifecycle of a Stream, and more, very useful: https://github.com/ceramicnetwork/ceramic/blob/master/SPECIFICATION.md 73 | 74 | # Completely Random Notes 75 | 76 | Keeping streams isn't universally required, so I think this may suffer the same problem as torrents, in that if something is considered forbidden content a govt authority can censor. I think that's probably by design but I found it interesting. 77 | 78 | Arweave isn't implemented yet. The denote it as "archiving" (clever distinction, Arweave is forever if the price is right) as opposed to what they are currently doing with IPFS/Filecoin which is more like pay-as-you-go storage. 79 | 80 | ##### Of interest: data withholding attacks.. 81 | 82 | They act like this isn't a big deal, but if I get someone's private keys and do this to them unknowningly I control their stream history. Imagine losing years worth of data due poor key management! 83 | 84 | Reference: 85 | 86 | One suggested attack on this conflict resolution system is a data withholding attack. In this scenario a user creates a stream, makes two conflicting updates and anchors one of them earlier than the other, but only publishes the data of the update that was anchored later. Now subsequent updates to the stream will be made on top of the second, published update. Every observer will accept these updates as valid since they have not seen the first update. However if the user later publishes the data of the earlier update, the stream will fork back to this update and all of the other updates made to the stream will be invalidated. 87 | 88 | This is essentially a double spend attack which is the problem that blockchains solve. However since identities have only one owner, the user, this is less of a problem. In this case, a "double spend" would cause the user to lose all history and associations that have accrued on their identity, which they are naturally disincentivized to do. 89 | 90 | In the case of organizational identities this is more of a problem, e.g. if an old admin of the org wants to cause trouble. This can be solved by introducing "heavy anchors" which rely more heavily on some on-chain mechanism. For example, a smart contract or a DAO that controls the identity. 91 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lit-ceramic-sdk", 3 | "version": "1.1.13", 4 | "description": "An integration of Lit Protocol with Ceramic Network", 5 | "license": "MIT", 6 | "repository": "LIT-Protocol/CeramicIntegration", 7 | "main": "dist/index.js", 8 | "keywords": [ 9 | "lit", 10 | "ceramic", 11 | "package" 12 | ], 13 | "scripts": { 14 | "build": "tsc", 15 | "build:docs": "documentation build src/integration.ts --parse-extension ts -f md -o documentation/integration.md --shallow && documentation build src/lit.ts --parse-extension ts -f md -o documentation/lit.md --shallow && documentation build src/ceramic.ts --parse-extension ts -f md -o documentation/ceramic.md --shallow && documentation build src/client.ts --parse-extension ts -f md -o documentation/client.md --shallow && doctoc README.md" 16 | }, 17 | "dependencies": { 18 | "@3id/connect": "^0.1.6", 19 | "@ceramicnetwork/3id-did-resolver": "^1.2.7", 20 | "@ceramicnetwork/common": "^1.1.0", 21 | "@ceramicnetwork/http-client": "^1.0.7", 22 | "@ceramicstudio/idx": "^0.12.1", 23 | "@ceramicstudio/idx-tools": "^0.11.0", 24 | "dag-jose": "^0.3.0", 25 | "dids": "^2.1.0", 26 | "documentation": "^13.2.5", 27 | "http-server": "^14.0.0", 28 | "key-did-resolver": "^1.2.0", 29 | "lit-js-sdk": "^1.1.121", 30 | "multiformats": "~4.6.1", 31 | "skynet-js": "^4.0.5-beta", 32 | "typescript": "^4.5.4", 33 | "uint8arrays": "^3.0.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/ceramic.ts: -------------------------------------------------------------------------------- 1 | import type { CeramicApi } from "@ceramicnetwork/common"; 2 | import Ceramic from "@ceramicnetwork/http-client"; 3 | import { Caip10Link } from "@ceramicnetwork/stream-caip10-link"; 4 | import { TileDocument } from "@ceramicnetwork/stream-tile"; 5 | import { DID } from "dids"; 6 | import ThreeIdResolver from "@ceramicnetwork/3id-did-resolver"; 7 | import KeyDidResolver from "key-did-resolver"; 8 | import { createIDX } from "./idx"; 9 | import { getProvider, getAddress } from "./wallet"; 10 | import { ResolverRegistry } from "did-resolver"; 11 | import { decodeb64, encodeb64, blobToBase64 } from "./lit"; 12 | 13 | declare global { 14 | interface Window { 15 | ceramic?: CeramicApi; 16 | [index: string]: any; 17 | } 18 | } 19 | 20 | /** 21 | * Authenticate for Lit + Ceramic. 22 | * Creates a CeramicApi object on the ceramic testnet 23 | * 24 | * @returns {Promise} ceramicPromise pass in _createCeramic() promise 25 | */ 26 | export async function _createCeramic( 27 | ceramicNodeUrl: string 28 | ): Promise { 29 | const ceramic = new Ceramic(ceramicNodeUrl); 30 | window.ceramic = ceramic; 31 | window.TileDocument = TileDocument; 32 | window.Caip10Link = Caip10Link; 33 | 34 | return Promise.resolve(ceramic as CeramicApi); 35 | } 36 | 37 | /** 38 | * Authenticate for Lit + Ceramic. 39 | * This uses a wallet provider to interact with the user's wallet 40 | * Once the user has authorized, the address is retrieved and the 41 | * decentralized identity is created. An IDX is also created for 42 | * convenience. 43 | * 44 | * @param {Promise} ceramicPromise pass in _createCeramic() promise 45 | * @returns {Promise>} Promise of ceramic IDX ID, ceramic object 46 | * and user's ETH Address 47 | */ 48 | export async function _authenticateCeramic( 49 | ceramicPromise: Promise 50 | ): Promise> { 51 | console.log("authenticate Ceramic!"); 52 | 53 | const provider = await getProvider(); 54 | const [ceramic, address] = await Promise.all([ceramicPromise, getAddress()]); 55 | const keyDidResolver = KeyDidResolver.getResolver(); 56 | const threeIdResolver = ThreeIdResolver.getResolver(ceramic); 57 | const resolverRegistry: ResolverRegistry = { 58 | ...threeIdResolver, 59 | ...keyDidResolver, 60 | }; 61 | const did = new DID({ 62 | provider: provider, 63 | resolver: resolverRegistry, 64 | }); 65 | 66 | await did.authenticate(); 67 | await ceramic.setDID(did); 68 | const idx = createIDX(ceramic); 69 | window.did = ceramic.did; 70 | return Promise.resolve([idx.id, ceramic, address]); 71 | } 72 | 73 | /** 74 | * Write to Ceramic. This function takes in an auth and what one would 75 | * like written and then sends it to a ceramic node in the proper format 76 | * @param {any[]} auth is the authentication passed via the persons wallet 77 | * @param {any[]} array of encrypted key, symkey, accessControlConditions, and chain 78 | * @returns {Promise} promise with the ceramic streamID, can be used to look up data 79 | */ 80 | export async function _writeCeramic( 81 | auth: any[], 82 | toBeWritten: any[] 83 | ): Promise { 84 | if (auth) { 85 | const ceramic = auth[1]; 86 | const toStore = { 87 | encryptedZip: toBeWritten[0], 88 | symKey: toBeWritten[1], 89 | accessControlConditions: toBeWritten[2], 90 | chain: toBeWritten[3], 91 | accessControlConditionType: toBeWritten[4], 92 | }; 93 | const doc = await TileDocument.create(ceramic, toStore, { 94 | // controllers: [concatId], 95 | family: "doc family", 96 | }); 97 | return doc.id.toString(); 98 | } else { 99 | console.error("Failed to authenticate in ceramic WRITE"); 100 | return "error"; 101 | } 102 | } 103 | 104 | export async function _updateCeramic( 105 | auth: any[], 106 | streamId: String, 107 | newContent: any[] 108 | ): Promise { 109 | if (auth) { 110 | const ceramic = auth[1]; 111 | const toStore = { 112 | encryptedZip: encodeb64(newContent[0]), 113 | symKey: encodeb64(newContent[1]), 114 | accessControlConditions: newContent[2], 115 | chain: newContent[3], 116 | accessControlConditionType: newContent[4], 117 | }; 118 | 119 | const doc = await TileDocument.load(ceramic, streamId.valueOf()); 120 | 121 | console.log( 122 | "$$$kl - loaded previous ceramic data from StreamID: ", 123 | streamId.valueOf() 124 | ); 125 | console.log("$$$kl - previous doc: ", doc); 126 | console.log("$$$kl - new access control conditions: ", newContent[1]); 127 | await doc.update(toStore); 128 | console.log("$$$kl - new doc: ", doc); 129 | return "updated access conditions stored in Ceramic"; 130 | } else { 131 | console.error("Failed to authenticate in ceramic WRITE"); 132 | return "error"; 133 | } 134 | } 135 | 136 | /** 137 | * Read to Ceramic. This function takes in an auth and the streamID of the desired data and then sends it to a ceramic node in the proper format getting back a promised string of whatever was stored 138 | * 139 | * @param {any[]} auth is the authentication passed via the user's wallet 140 | * @param {String} streamId ID hash of the stream 141 | * @returns {Promise} promise with the ceramic streamID's output 142 | */ 143 | export async function _readCeramic( 144 | auth: any[], 145 | streamId: String 146 | ): Promise { 147 | if (auth) { 148 | const ceramic = auth[1]; 149 | const stream = await ceramic.loadStream(streamId); 150 | return stream.content; 151 | } else { 152 | console.error("Failed to authenticate in ceramic READ"); 153 | return "error"; 154 | } 155 | } 156 | 157 | /** 158 | * Decode info from base64. Data is stored in base64 to make upload to ceramic 159 | * more seamless. This function decodes it so it can be decrypted with Lit in 160 | * the next step in the read and decrypt process 161 | * 162 | * @param {string} response response received from ceramic streamID 163 | * @returns {Promise} array of decrypted zip and symmetric key + AAC and chain 164 | */ 165 | export async function _decodeFromB64(response: string) { 166 | // data is encoded in base64, decode 167 | // const jason = JSON.stringify(response); 168 | try { 169 | // @ts-ignore 170 | const enZip = response["encryptedZip"]; 171 | const deZip = decodeb64(enZip); 172 | 173 | // @ts-ignore 174 | const enSym = response["symKey"]; 175 | const deSym = decodeb64(enSym); 176 | 177 | // @ts-ignore 178 | const accessControlConditions = response["accessControlConditions"]; 179 | // @ts-ignore 180 | const chain = response["chain"]; 181 | // @ts-ignore 182 | const accessControlConditionType = response["accessControlConditionType"]; 183 | return [ 184 | deZip, 185 | deSym, 186 | accessControlConditions, 187 | chain, 188 | accessControlConditionType, 189 | ]; 190 | } catch (error) { 191 | return "There was an error decrypting, is it possible you inputted the wrong streamID?"; 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/client.ts: -------------------------------------------------------------------------------- 1 | import * as LitJsSdk from "lit-js-sdk"; 2 | 3 | /** 4 | * Starts Lit Client in background. should be run upon starting of project. 5 | * 6 | * @param {Window} window the window of the project, to which it attaches 7 | * a litNodeClient 8 | */ 9 | export async function _startLitClient(window: Window) { 10 | console.log("Starting Lit Client..."); 11 | const client = new LitJsSdk.LitNodeClient(); 12 | client.connect(); 13 | window.litNodeClient = client; 14 | } 15 | -------------------------------------------------------------------------------- /src/idx.ts: -------------------------------------------------------------------------------- 1 | import type { CeramicApi } from '@ceramicnetwork/common' 2 | import { IDX } from '@ceramicstudio/idx' 3 | 4 | declare global { 5 | interface Window { 6 | idx?: IDX 7 | } 8 | } 9 | 10 | export function createIDX(ceramic: CeramicApi): IDX { 11 | const idx = new IDX({ ceramic }) 12 | window.idx = idx 13 | return idx 14 | } 15 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // test code to start module 2 | 3 | import { Integration } from "./integration"; 4 | 5 | export { Integration }; 6 | -------------------------------------------------------------------------------- /src/integration.ts: -------------------------------------------------------------------------------- 1 | // Don't forget to rebuild 2 | import { createIDX } from "./idx"; 3 | import type { CeramicApi } from "@ceramicnetwork/common"; 4 | import type { DID } from "dids"; 5 | import { _encryptWithLit, _decryptWithLit, _saveEncryptionKey } from "./lit"; 6 | import { _startLitClient } from "./client"; 7 | import { 8 | _authenticateCeramic, 9 | _createCeramic, 10 | _writeCeramic, 11 | _readCeramic, 12 | _decodeFromB64, 13 | _updateCeramic, 14 | } from "./ceramic"; 15 | 16 | declare global { 17 | interface Window { 18 | did?: DID; 19 | } 20 | } 21 | export class Integration { 22 | ceramicPromise: Promise; 23 | chain: String; 24 | 25 | constructor( 26 | ceramicNodeUrl: string = "https://ceramic-clay.3boxlabs.com", 27 | chainParam: String = "ethereum" 28 | ) { 29 | this.chain = chainParam; 30 | // console.log("setting chain to ", this.chain); 31 | this.ceramicPromise = _createCeramic(ceramicNodeUrl); 32 | } 33 | 34 | startLitClient(window: Window) { 35 | _startLitClient(window); 36 | } 37 | 38 | /** 39 | * Encrypts using Lit and then writes using Ceramic 40 | * whatever the module user inputs (as long as it is a string for now) 41 | * 42 | * @param {String} toEncrypt what the module user wants to encrypt and store on ceramic 43 | * @param {Array} accessControlConditions the access control conditions that govern who is able to decrypt this data. See the docs here for examples: https://developer.litprotocol.com/docs/SDK/accessControlConditionExamples 44 | * @param {String} accessControlConditionType the access control condition type you are using. Pass `accessControlConditions` for traditional access control conditions. This is the default if you don't pass anything. Pass `evmContractConditions` for custom smart contract access control conditions 45 | * @returns {Promise} A promise that resolves to a streamID for the encrypted data that's been stored 46 | */ 47 | async encryptAndWrite( 48 | toEncrypt: String, 49 | accessControlConditions: Array, 50 | accessControlConditionType: String = "accessControlConditions" 51 | ): Promise { 52 | if ( 53 | accessControlConditionType !== "accessControlConditions" && 54 | accessControlConditionType !== "evmContractConditions" 55 | ) { 56 | throw new Error( 57 | "accessControlConditionType must be accessControlConditions or evmContractConditions" 58 | ); 59 | } 60 | try { 61 | const a = await _authenticateCeramic(this.ceramicPromise); 62 | const en = await _encryptWithLit( 63 | toEncrypt, 64 | accessControlConditions, 65 | this.chain, 66 | accessControlConditionType 67 | ); 68 | const wr = await _writeCeramic(a, en); 69 | return wr; 70 | } catch (error) { 71 | return `something went wrong encrypting: ${error}`; 72 | } 73 | } 74 | 75 | /** 76 | * Retrieves a stream and decrypts message then returns to user 77 | * 78 | * @param {String} streamID the streamID of the encrypted data the user wants to access 79 | * @returns {Promise} A promise that resolves to the unencrypted string of what was stored 80 | */ 81 | async readAndDecrypt(streamID: String): Promise { 82 | try { 83 | // makes certain DID/wallet has been auth'ed 84 | const a = await _authenticateCeramic(this.ceramicPromise); 85 | console.log("authenticated RnD: ", a); 86 | // read data and retrieve encrypted data 87 | const en = await _readCeramic(a, streamID); 88 | console.log("read from ceramic RnD: ", en); 89 | // decode data returned from ceramic 90 | const deco = await _decodeFromB64(en); 91 | console.log("data from ceramic: ", deco); 92 | // decrypt data that's been decoded 93 | const decrypt = await _decryptWithLit( 94 | deco[0], 95 | deco[1], 96 | deco[2], 97 | deco[3], 98 | deco[4] 99 | ); 100 | 101 | return decrypt; 102 | } catch (error) { 103 | console.log( 104 | `something went wrong decrypting: ${error} \n StreamID sent: ${streamID}` 105 | ); 106 | return "FALSE"; 107 | } 108 | } 109 | 110 | /** 111 | * Retrieves a stream and decrypts message then returns to user 112 | * 113 | * @param {String} streamID the streamID of the encrypted data that you want to update the access control conditions for 114 | * @param {Array} accessControlConditions the access control conditions that govern who is able to decrypt this data. Note that you cannot change the accessControlConditionType using this method, and you must use the same condition type that was used when you ran encryptAndWrite. See the docs here for examples of accessControlConditions: https://developer.litprotocol.com/docs/SDK/accessControlConditionExamples 115 | * @returns {Promise} A promise that resolves to the unencrypted string of what was stored 116 | */ 117 | async updateAccess( 118 | streamID: String, 119 | newAccessControlConditions: Array 120 | ): Promise { 121 | try { 122 | console.log("trying to update permissions for streamID: ", streamID); 123 | const a = await _authenticateCeramic(this.ceramicPromise); 124 | console.log("authenticated: ", a); 125 | const en = await _readCeramic(a, streamID); 126 | console.log("read from ceramic: ", en); 127 | // decode data returned from ceramic 128 | const deco = await _decodeFromB64(en); 129 | console.log("data from ceramic: ", deco); 130 | 131 | const result = await _saveEncryptionKey( 132 | newAccessControlConditions, 133 | deco[1], //encryptedSymmetricKey 134 | this.chain 135 | ); 136 | console.log("update access result: ", result); 137 | 138 | //deco mapping: 139 | // encryptedZip: Uint8Array, 140 | // encryptedSymmKey: Uint8Array, 141 | // accessControlConditions: Array, 142 | // chain: string, 143 | // accessControlConditionType: S 144 | 145 | // [ 146 | // encryptedZipBase64, 147 | // encryptedSymmetricKeyBase64, 148 | // accessControlConditions, 149 | // chain, 150 | // accessControlConditionType, 151 | // ] 152 | 153 | const newContent = [ 154 | deco[0], 155 | deco[1], 156 | newAccessControlConditions, 157 | deco[3], 158 | deco[4], 159 | ]; 160 | 161 | //save the access conditions back to Ceramic 162 | console.log( 163 | "saving new ceramic access conditions: ", 164 | newContent, 165 | newAccessControlConditions 166 | ); 167 | 168 | const result2 = await _updateCeramic(a, streamID, newContent); 169 | console.log("update ceramic access conditions: ", streamID, result); 170 | 171 | return result2; 172 | } catch (error) { 173 | return `something went wrong encrypting: ${error}`; 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /src/lit.ts: -------------------------------------------------------------------------------- 1 | // import LitJsSdk from 'lit-js-sdk' 2 | import * as LitJsSdk from "lit-js-sdk"; 3 | import { toString as uint8ArrayToString } from "uint8arrays/to-string"; 4 | 5 | /** 6 | * This function encodes into base 64. 7 | * it's useful for storing symkeys and files in ceramic 8 | * @param {Uint8Array} input a file or any data 9 | * @returns {string} returns a string of b64 10 | */ 11 | export function encodeb64(uintarray: any) { 12 | const b64 = Buffer.from(uintarray).toString("base64"); 13 | return b64; 14 | } 15 | 16 | /** 17 | * This function converts blobs to base 64. 18 | * for easier storage in ceramic 19 | * @param {Blob} blob what you'd like to encode 20 | * @returns {Promise} returns a string of b64 21 | */ 22 | export function blobToBase64(blob: Blob) { 23 | return new Promise((resolve, _) => { 24 | const reader = new FileReader(); 25 | reader.onloadend = () => 26 | resolve( 27 | // @ts-ignore 28 | reader.result.replace("data:application/octet-stream;base64,", "") 29 | ); 30 | reader.readAsDataURL(blob); 31 | }); 32 | } 33 | 34 | /** 35 | * This function decodes from base 64. 36 | * it's useful for decrypting symkeys and files in ceramic 37 | * @param {blob} input a b64 string 38 | * @returns {string} returns the data as a string 39 | */ 40 | export function decodeb64(b64String: any) { 41 | return new Uint8Array(Buffer.from(b64String, "base64")); 42 | } 43 | 44 | /** 45 | * encrypts a message with Lit returns required details 46 | * this obfuscates data such that it can be stored on ceramic without 47 | * non-permissioned eyes seeing what the data is 48 | * @param {String} aStringThatYouWishToEncrypt the clear text you'd like encrypted 49 | * @param {Array} accessControlConditions the access control conditions that govern who is able to decrypt this data. See the docs here for examples: https://developer.litprotocol.com/docs/SDK/accessControlConditionExamples 50 | * @param {String} chain the chain you'd like to use for checking the access control conditions 51 | * @param {String} accessControlConditionType the access control condition type you are using. Pass `accessControlConditions` for traditional access control conditions. This is the default if you don't pass anything. Pass `evmContractConditions` for custom smart contract access control conditions 52 | * @returns {Promise>} returns, in this order: encryptedZipBase64, encryptedSymmetricKeyBase64, accessControlConditions, chain 53 | */ 54 | export async function _encryptWithLit( 55 | aStringThatYouWishToEncrypt: String, 56 | accessControlConditions: Array, 57 | chain: String, 58 | accessControlConditionType: String = "accessControlConditions" 59 | ): Promise> { 60 | let authSig = await LitJsSdk.checkAndSignAuthMessage({ 61 | chain, 62 | }); 63 | const { encryptedZip, symmetricKey } = await LitJsSdk.zipAndEncryptString( 64 | aStringThatYouWishToEncrypt 65 | ); 66 | 67 | let encryptedSymmetricKey; 68 | 69 | if (accessControlConditionType === "accessControlConditions") { 70 | encryptedSymmetricKey = await window.litNodeClient.saveEncryptionKey({ 71 | accessControlConditions, 72 | symmetricKey, 73 | authSig: authSig, 74 | chain, 75 | permanant: false, 76 | }); 77 | } else if (accessControlConditionType === "evmContractConditions") { 78 | encryptedSymmetricKey = await window.litNodeClient.saveEncryptionKey({ 79 | evmContractConditions: accessControlConditions, 80 | symmetricKey, 81 | authSig: authSig, 82 | chain, 83 | permanant: false, 84 | }); 85 | } else { 86 | throw new Error( 87 | "accessControlConditionType must be accessControlConditions or evmContractConditions" 88 | ); 89 | } 90 | const encryptedZipBase64 = await blobToBase64(encryptedZip); 91 | const encryptedSymmetricKeyBase64 = encodeb64(encryptedSymmetricKey); 92 | 93 | return [ 94 | encryptedZipBase64, 95 | encryptedSymmetricKeyBase64, 96 | accessControlConditions, 97 | chain, 98 | accessControlConditionType, 99 | ]; 100 | } 101 | 102 | /** 103 | * decrypt encrypted zip and symmetric key using the lit protocol 104 | * @param {Uint8Array} encryptedZip encrypted data that will be converted into a string 105 | * @param {Uint8Array} encryptedSymmKey symmetric key 106 | * @param {Array} accessControlConditions conditions that determine access 107 | * @param {String} chain the chain you'd like to use for checking the access control conditions 108 | * @param {String} accessControlConditionType the access control condition type you are using. Pass `accessControlConditions` for traditional access control conditions. This is the default if you don't pass anything. Pass `evmContractConditions` for custom smart contract access control conditions 109 | * @returns {Promise} promise with the decrypted string 110 | */ 111 | 112 | export async function _decryptWithLit( 113 | encryptedZip: Uint8Array, 114 | encryptedSymmKey: Uint8Array, 115 | accessControlConditions: Array, 116 | chain: string, 117 | accessControlConditionType: String = "accessControlConditions" 118 | ): Promise { 119 | let authSig = await LitJsSdk.checkAndSignAuthMessage({ 120 | chain, 121 | }); 122 | // encrypted blob, sym key 123 | console.log("encryptedSymKey", encryptedSymmKey); 124 | const toDecrypt = uint8ArrayToString(encryptedSymmKey, "base16"); 125 | console.log("toDecrypt", toDecrypt); 126 | // decrypt the symmetric key 127 | let decryptedSymmKey; 128 | if (accessControlConditionType === "accessControlConditions") { 129 | decryptedSymmKey = await window.litNodeClient.getEncryptionKey({ 130 | accessControlConditions, 131 | toDecrypt, 132 | chain, 133 | authSig, 134 | }); 135 | } else if (accessControlConditionType === "evmContractConditions") { 136 | decryptedSymmKey = await window.litNodeClient.getEncryptionKey({ 137 | evmContractConditions: accessControlConditions, 138 | toDecrypt, 139 | chain, 140 | authSig, 141 | }); 142 | } 143 | console.log("decryptedSymKey", decryptedSymmKey); 144 | 145 | // decrypt the files 146 | const decryptedFiles = await LitJsSdk.decryptZip( 147 | new Blob([encryptedZip]), 148 | decryptedSymmKey 149 | ); 150 | const decryptedString = await decryptedFiles["string.txt"].async("text"); 151 | return decryptedString; 152 | } 153 | 154 | // litCeramicIntegration.saveEncryptionKey({ 155 | // accessControlConditions: newAccessControlConditions, 156 | // encryptedSymmetricKey, 157 | // authSig, 158 | // chain, 159 | // permanant: false, 160 | // }); 161 | export async function _saveEncryptionKey( 162 | newAccessControlConditions: Array, 163 | encryptedSymmetricKey: Uint8Array, 164 | chain: String 165 | ): Promise { 166 | let authSig = await LitJsSdk.checkAndSignAuthMessage({ 167 | chain, 168 | }); 169 | // encrypted blob, sym key 170 | // console.log("encryptedSymKey entered: ", encryptedSymmetricKey); 171 | // console.log("authSig: ", authSig); 172 | 173 | // const newAccessControlConditions = [ 174 | // { 175 | // contractAddress: '', 176 | // standardContractType: '', 177 | // chain: 'polygon', 178 | // method: '', 179 | // parameters: [ 180 | // ':userAddress', 181 | // ], 182 | // returnValueTest: { 183 | // comparator: '=', 184 | // value: '0x0Db0448c95cad6D82695aC27022D20633C81b387' 185 | // }, 186 | // }, 187 | // ] 188 | 189 | const newEncryptedSymmetricKey = await window.litNodeClient.saveEncryptionKey( 190 | { 191 | accessControlConditions: newAccessControlConditions, 192 | encryptedSymmetricKey, 193 | authSig, 194 | chain, 195 | permanant: false, 196 | } 197 | ); 198 | console.log("updated the access control condition"); 199 | return newEncryptedSymmetricKey; 200 | } 201 | -------------------------------------------------------------------------------- /src/wallet.ts: -------------------------------------------------------------------------------- 1 | import { ThreeIdConnect, EthereumAuthProvider } from "@3id/connect"; 2 | import type { DIDProvider } from "dids"; 3 | import LitJsSdk from "lit-js-sdk"; 4 | 5 | // @ts-ignore 6 | export const threeID = new ThreeIdConnect(); 7 | 8 | export async function getProvider(): Promise { 9 | // const ethProvider = await web3Modal.connect() 10 | // const addresses = await ethProvider.enable() 11 | const { web3, account } = await LitJsSdk.connectWeb3(); 12 | await threeID.connect(new EthereumAuthProvider(web3.provider, account)); 13 | return threeID.getDidProvider(); 14 | } 15 | 16 | export async function getAddress(): Promise { 17 | // const ethProvider = await web3Modal.connect() 18 | // const addresses = await ethProvider.enable() 19 | // const addr = addresses[0] 20 | const { web3, account } = await LitJsSdk.connectWeb3(); 21 | return account; 22 | } 23 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */, 8 | "module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, 9 | // "lib": [], /* Specify library files to be included in the compilation. */ 10 | // "allowJs": true, /* Allow javascript files to be compiled. */ 11 | // "checkJs": true, /* Report errors in .js files. */ 12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ 13 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | "outDir": "./dist" /* Redirect output structure to the directory. */, 18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | // "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true /* Enable all strict type-checking options. */, 29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | // "strictNullChecks": true, /* Enable strict null checks. */ 31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 43 | // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */ 44 | // "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */ 45 | 46 | /* Module Resolution Options */ 47 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 48 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 49 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 50 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 51 | // "typeRoots": [], /* List of folders to include type definitions from. */ 52 | // "types": [], /* Type declaration files to be included in compilation. */ 53 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 54 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 55 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 56 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 57 | 58 | /* Source Map Options */ 59 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 60 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 61 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 62 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 63 | 64 | /* Experimental Options */ 65 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 66 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 67 | 68 | /* Advanced Options */ 69 | "skipLibCheck": true /* Skip type checking of declaration files. */, 70 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /typings-custom/documentation.d.ts: -------------------------------------------------------------------------------- 1 | declare module "documentation"; 2 | declare module "lit-js-sdk"; 3 | --------------------------------------------------------------------------------