wise-js
TypeScript icon, indicating that this package has built-in type declarations

1.1.2 • Public • Published

wise-js was renamed to walletify-js on April 2023

wise-js

Construct and decode authentication requests for Stacks apps.

This package provides the auth logic used by the WISE App. If you're looking to integrate WISE authentication into your react-native app, wise-js provides a simple API using Stacks. if you're not familiar with Stacks, You should first take a look into Stacks Authentication.

Wise

Installation

npm i --save wise-js

or

yarn add wise-js

Usage

  1. For react-native use this guide to install react-native-crypto.

    The react-native-crypto is A port of node's crypto module to React Native.

  2. Include the app config into your app, and change the appDomain to your domain.

import {
  AppConfig,
} from 'wise-js';

const appDomain = 'https://example.com';
const manifestURIPath = '/manifest.json';
const scopes = ['store_write', 'publish_data'];
const appConfig = new AppConfig(scopes, appDomain, undefined, manifestURIPath);

The app domain is the URL to your website/app. This is how the Stacks authentication system identifies apps and determines what credentials to provide. Changing the appDomain is equivalent to changing the app.

scopes where you set the basic permissions for your app to read and store user data. If your app will allow users to share data with other users, you will need an additional publish_data permission.

manifestURIPath is the location of your app manifest file. This file contains information about your app that is shown to the user during authentication.

  1. Make a sessionStore class to customize where your authentication data is located. for example, this is the sessionStore class that implements @react-native-async-storage/async-storage.
import AsyncStorage from '@react-native-async-storage/async-storage';
import {
  SessionData,
  SessionOptions,
  SessionDataStore,
} from 'wise-js';

const LOCALSTORAGE_SESSION_KEY = 'wise-session';

export class AsyncStorageStore extends SessionDataStore {
  key: string;

  constructor(sessionOptions?: SessionOptions) {
    super(sessionOptions);
    if (
      sessionOptions
            && sessionOptions.storeOptions
            && sessionOptions.storeOptions.localStorageKey
            && typeof sessionOptions.storeOptions.localStorageKey === 'string'
    ) {
      this.key = sessionOptions.storeOptions.localStorageKey;
    } else {
      this.key = LOCALSTORAGE_SESSION_KEY;
    }
    this.init();
  }

  async init() {
    const data = await this.getData(this.key);
    if (!data) {
      const sessionData = new SessionData({});
      this.setSessionData(sessionData);
    }
  }

  async getData(key: string) {
    return AsyncStorage.getItem(key);
  }

  async getSessionData(): Promise<SessionData> {
    const data = await AsyncStorage.getItem(this.key);
    if (!data) {
      console.log('No session data was found in localStorage');
      return {};
    }
    // @ts-ignore
    const dataJSON = JSON.parse(data);
    return SessionData.fromJSON(dataJSON);
  }

  async setSessionData(session: SessionData) {
    await AsyncStorage.setItem(this.key, session.toString());
  }

  async deleteSessionData() {
    await AsyncStorage.removeItem(this.key);
    await this.setSessionData(new SessionData({}));
  }
}

Important Note: Don't forget to install @react-native-async-storage/async-storage

  1. Use the sessionStorage and appConfig to create your userSession;
import {
  WiseUserSession,
} from 'wise-js';

const userSession = new WiseUserSession({
    appConfig,
    sessionStore,
});

We will also initiate a UserSession object using the previous configurations.

  1. Use the userSession to initiate authentication flow.
import {
  useCallback,
  useEffect,
  useState,
} from 'react';
import {
  Alert,
  DeviceEventEmitter,
  Linking,
  Platform,
} from 'react-native';
import {
  getParameterByName,
} from 'wise-js';

export const useAuthentication = () => {
  const [pendingAuthentication, setPendingAuthentication] = useState<boolean>(false);

  const createSession = useCallback(async () => {
    // Method to check if the user is already authenticated.
    const signedIn = await userSession.isUserSignedIn();
    if (signedIn) {
      // Method to retrieve the user's profile data
      const sessionData = await userSession.loadUserData();
      console.warn('Use is logged in with session data', sessionData);
    } else {
      console.warn('User is not logged In');
    }
  }, []);
   const resumeAuthentication = useCallback(
           (linkingUrl: string) => {
              Linking.canOpenURL(linkingUrl)
                      .then(supported => {
                         if (supported) {
                            setPendingAuth(true);
                            const authResponse = getParameterByName('authResponse', linkingUrl);
                            setLoading();
                            userSession
                                    .handlePendingSignIn(authResponse || '')
                                    .then(() => {
                                       createSession();
                                       setPendingAuth(false);
                                    })
                                    .catch(() => {
                                       setFailure();
                                       setPendingAuth(false);
                                    });
                         }
                      })
                      .catch(() => {
                         setFailure();
                         setPendingAuth(false);
                      });
           },
           [createSession],
   );
  useEffect(() => {
    createSession();
    // setup listener for url changes.
    const subscription = DeviceEventEmitter.addListener('url', ({ url: linkingUrl }) => {
      if (e.url && !pendingAuthentication) {
         resumeAuthentication(linkingUrl);
      }
    });
    return () => subscription.remove();
  }, []);
  
   useEffect(() => {
      const getUrlAsync = async () => {
         // Get the deep link used to open the app for first time
         const initialUrl = await Linking.getInitialURL();
         resumeAuthentication(initialUrl || '');
      };

      getUrlAsync();
   }, []);
   
  const signIn = useCallback(async () => {
    // Method to generate generate the authentication request payload.
     const url = await userSession.generateAuthURL();
    // This part where you communicate with WISE to authenticate.
     Linking.openURL(url);
  }, []);
  
  const signOut = useCallback(async () => {
    await userSession.signUserOut();
  }, []);

  return {
    signIn,
    signOut,
  };
};
  1. Make a manifest.json file on your hosting domain.
{
    short_name: "Pravica",
    name: "Pravica",
    icons: [
        {
            src: "https://app.pravica.io/new-logo.png",
            sizes: "64x64 32x32 24x24 16x16",
            type: "image/png"
        }
    ],
    start_url: "https://app.pravica.io",
    display: "standalone",
    theme_color: "#000000",
    background_color: "#2679ff"
}
  1. To initiate Stacks Gaia client with your app.
import {
   WiseCustomStorage,
} from 'wise-js';

export const wiseStorage = new WiseCustomStorage({
  userSession,
});

Gaia storage provides a way for users to save both public and private data off-chain while retaining complete control over it.

  1. To enable routing back to your app from WISE you have to configure the universal links for (IOS) and app links for (Android).

Create a folder on your hosting domain root with the name .well-known to put the universal links for (IOS) and app links for (Android) configuration files.

1- For IOS:

  • create a file with the name ‘apple-app-site-association’:
{
    "applinks": {
        "apps": [],
        "details": [
            {
                "appID": "MXLF5SQD6Q.io.pravica",
                "paths": [ "*" ]
            }
        ]
    }
}
  • Replace MXLF5SQD6Q with your Team ID you can get it from https://developer.apple.com.

  • Replace io.pravica with your Bundle Identifier.

  • Then Add the Associated Domains Entitlement to Your App.

    To set up the entitlement in your app, open the target’s Signing & Capabilities tab in Xcode and add the Associated Domains capability and fill in the domain of your site with the prefix applinks:

    img.png -Add this code to your AppDelegate.m:

    #import "RCTLinkingManager.h"
    
    - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
      restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
      {
      return [RCTLinkingManager application:application
                       continueUserActivity:userActivity
                         restorationHandler:restorationHandler];
      }
    
    

For Reference: https://developer.apple.com/documentation/Xcode/supporting-associated-domains.

2- For Android:

  • create a file with the name assetlinks.json:
[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "io.pravica",
    "sha256_cert_fingerprints": ["DB:1C:4B:5C:BA:2D:DD:6E:56:47:87:93:FA:D0:7E:BF:4B:15:DF:71:99:19:73:8E:3F:2F:54:F0:C8:8B:FC:C4"]
  }
}]
  • Replace io.pravica with your Bundle Identifier.
  • Replace sha256_cert_fingerprints with your fingerprint. The SHA256 fingerprints of your app’s signing certificate. You can use the following command to generate the fingerprint via the Java keytool.
keytool -list -v -keystore my-release-key.keystore
  • To enable link handling verification for your app, set android:autoVerify="true" in any one of the web URL intent filters in your app manifest that include the android.intent.action.VIEW intent action and android.intent.category.BROWSABLE intent category, as shown in the following manifest code snippet:
<activity ...>

    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="https" android:host="app.pravica.io"/>
    </intent-filter>

</activity>
  • Replace app.pravica.io with your domain URL.

For Reference: https://developer.android.com/training/app-links/verify-site-associations.

Package Sidebar

Install

npm i wise-js

Weekly Downloads

0

Version

1.1.2

License

GPL-3.0-or-later

Unpacked Size

1.1 MB

Total Files

35

Last publish

Collaborators

  • pravica