This is all about how to develop this next-dapp account plugin, not how to develop a next-dapp based project itself.
Next Dapp itself is based upon Next.js / React and heavily powered by Recoil state management library. Other major dependencies are Ramda and Rebass.
The core plugin is located at @nextdapp/core.
A working example can be found here.
You will need the nextdapp command line tool for development. Install it globally with npm
or yarn
.
I will use yarn
throughout this document.
sudo npm i -g nextdapp
or
yarn global add nextdapp
A demo directory is nested inside the plugin directory. They are separate projects, so you need to install the required packages for the both projects separately.
# clone
git clone https://github.com/warashibe/nd-account.git
# move to the plugin dixrectory and install node modules with yarn
cd nd-account && yarn
# move to the demo directory and install node modules with yarn
cd demo && yarn
nd/conf.js
is ignored by .gitignore
, so you need to copy nd/conf.sample.js
to nd/conf.js
and modify it according to your needs. For now, keep all the dummy data even if you don't use some login methods. The plugin throws an error, if something is missing. This behavior will be taken care of in the future.
cp nd/conf.sample.js nd/conf.js
import { mergeAll } from "ramda"
let local = {}
try {
local = require("nd/conf.local")
} catch (e) {}
const prod = {
id: "next-dapp",
html: {
title: "Next Dapp | The Bridge between Web 2.0 and 3.0",
description:
"Next Dapp is a web framework to progressively connect web 2.0 with 3.0.",
image: "https://picsum.photos/1000/500",
"theme-color": "#03414D"
},
firebase: {
name: "xxx-xxx",
id: "xxx-xxx",
key: "xxxxxxx",
sender: "123456789",
region: "us-central1"
},
web3: {
network: "3" // Ropsten Testnet
},
alis: {
client_id: "123456789,
redirect_uri: "http://localhost:3000/"
},
steem: {
redirect_uri: "http://localhost:3000/",
app: "ocrybit"
},
uport: {
name_field: "氏名又は名称",
id_field: "交付番号",
appName: "暗号資産古物商協会",
did: "did:ethr:0x62507aa089182659ff595266e3c1de2975a51780",
verified: "古物商許可証テストネット"
}
}
module.exports = mergeAll([prod, local])
Sensitive data such as private keys are not to be mixed with the configurations above, use .env
for credintials.
touch .env
UPort requires my private key and not configurable for anyone other than me at the moment.
# if not used, you don't need alis and uport credentials
ALIS_CLIENT_SECRET=xxxxxxxxx
UPORT_PRIVATE_KEY=xxxxxxxx
WEB3_INFURA=https://ropsten.infura.io/v3/xxxxxxx
UPORT_RPCURL=https://mainnet.infura.io/v3/xxxxxxxx
Create a new project if you don't have one to use for the development. Do not overwrite any files during the initialization such as firebase/firestore.rules
. If you keep pressing Enter
without changing the default options, you won't overwrite anything.
Alternatively, create one from the web console https://console.firebase.google.com. Then run below.
You need to set a cloud resource location by setting up Firestore
via the web console above.
You need to install firebase-tools
and set it up first. Refer to this page.
npm install -g firebase-tools
Once you set it up and log in, proceed.
cd firebase && firebase init
- Google, Twitter, Github, Facebook can be set up via Firebse console.
- ALIS: Register an OAuth app from here, and set the redirect URI to
http://localhost:3000/
. - STEEM: Set up steemconnect somehow... I forgot how :)
- Metamask, Authereum: You will need the
@nextdapp/web3
plugin to make it work. - UPort: It only works with my private key at the moment, to be extended.
firebase deploy --only firestore:rules
Functions are only compatible with node v.10.x. Use nvm
to temporarily switch versions.
nvm
can be installed by yarn
or npm
yarn global add nvm
Create /firebase/functions/env.json
and modify as shown below. If you are not using the web3 based login methos, just copy and paste below for dummy data.
cd functions && nvm use 10 && yarn && touch env.json
/firebase/functions/env.json
{
"web3": {
"infura": "https://ropsten.infura.io/v3/xxxxx"
},
"uport": {
"name_field": "氏名又は名称",
"id_field": "交付番号",
"appName": "暗号資産古物商協会",
"did": "did:ethr:0x62507aa089182659ff595266e3c1de2975a51780",
"privateKey":
"xxxxxxx",
"rpcUrl": "https://mainnet.infura.io/v3/xxxxx",
"verified": "古物商許可証テストネット"
}
}
Upload env to your remote Cloud Functions environment. This command will do the magic.
firebase functions:config:set env="$(cat env.json)"
Deploy functions.
cd ..
firebase deploy --only functions
cd ../demo
yarn dev
Example: url
is optional.
{
key: "alis",
name: "ALIS",
bg: "#232538",
url: v => `https://alis.to/users/${v.username}`
}
2. add two types of icons to /static/images directory
Name them github-white.png
(Login Button) and github.png
(Link to User Account).
3. add a function to const login_with
in /src/account.js
This will redirect the user to alis.to for an OAuth2.0 authentication flow.
You automatically get { set, values, conf }
as the arguments.
alis: async ({ conf }) => {
const code_verifier = get_code_verifier()
const code_challenge = get_code_challenge(code_verifier)
const purl = `https://alis.to/oauth-authenticate?client_id=${
conf.alis.client_id
}&redirect_uri=${encodeURIComponent(
conf.alis.redirect_uri
)}&scope=write&code_challenge=${code_challenge}`
setCookie(null, "alis_verifier", code_verifier, { path: "/" })
window.location.href = purl
},
Next-Dapp utilizes Recoil - the Facebook official state management library.
If you change global states, you need to list them in the first argument like done below -["processing$util"]
.
set
can change globally reactive states in this way.
If you need your own global states, define them in /src/init.js, and add them to /nextdapp.json. If you define your_state
, it will namespaced and become your_state$account
throughout the app.
export const check_alis = [
["processing$util"],
async ({ val: { router }, state$, set }) => {
const code = router.query.code
if (isNil(code)) return
set(true, "processing$util")
const cookies = parseCookies()
const alis_verifier = cookies.alis_verifier
let user = await checkUser(state$)
let login_url = `/api/alis-oauth_account?code=${code}&verifier=${
cookies.alis_verifier
}`
await _login_with({ login_url, set, state$, provider: "alis" })
router.replace(router.pathname, router.pathname, { shallow: true })
}
]
Pick necessary fields to form a user data from add
.
name
, image
and description
are preffered to be assigned.
const name_map = {
"alis.to": "alis",
const link_converter = {
"alis.to": (_u, add) =>
mergeLeft(
{
name: add.user_display_name,
image: add.icon_image_url,
description: add.self_introduction,
username: add.user_id
},
_u
),
Plugin functions will be automatically namespaced. check_alis
becomes fn.check_alis$account
.
Example: /demo/page/index.js
useEffect(
() => {
if (hasPath(["router", "query", "code"])(props)) {
isFirebase(props.conf).then(() => {
fn.check_alis$account({ router: props.router })
})
}
},
[props.router.query]
)
Don't forget to bind the function to the Component.
[
"user$account",
"uport$account",
"processing$util",
"changeUser$account",
"check_alis$account", // <= bind to Component
"linkAccount$account",
"unlinkAccount$account"
]
7. write the logic to generate custom_token using Next.js api or/and Cloud Functions.
For alis, refer to /src/api/alis-oauth.js and exports login
in /firebase/functions/index.js.
If you need any credentials to set for Cloud Functions, refer back to create env.json and deploy environmental variables and functions
Public configurations for Next.js app can be set as described in 2. Copy and Modify conf.sample.js file
Credentials for Next.js app can be set as described in 4. Setup credentials as env values
{
"epics": [ "changeUser", "logout", "logout_authereum", "login", "check_alis", "deleteAccount", "linkAccount", "unlinkAccount" ],
"props": [ "user", "user_init", "uport", "_user" ],
"api": { "apiAlisOauth": "alis-oauth", "apiSteemOauth": "steem-oauth", "apiUportLogin": "uport-login" },
"functions": { "nd-account-functions": [ "loginUport", "loginMetamask", "loginAuthereum", "login" ] },
"env": [ "ALIS_CLIENT_SECRET", "UPORT_PRIVATE_KEY", "WEB3_INFURA", "UPORT_RPCURL" ],
"components": ["Login", "UPort", "Profile", "LinkAccount"]
}
yarn build
Use .. noinstall
for local rebuild and update. It will link to the updated local file without installing the node package.
You don't need them when updating directly from node package registry
.
cd demo
nextdapp remove @nextdapp/account .. noinstall
nextdapp add @nextdapp/account .. noinstall