diff --git a/src/didcommv2/MessageReceiver.ts b/src/didcommv2/MessageReceiver.ts index 9bad532..914a735 100644 --- a/src/didcommv2/MessageReceiver.ts +++ b/src/didcommv2/MessageReceiver.ts @@ -8,6 +8,7 @@ export async function receiveMessage(packMsg: any) { // TODO Process from_prior, thid y pthid // TODO return errors const type = JSON.parse(unpacked.message).type + logger(type) // Message dispatch switch (type) { diff --git a/src/protocols/basicmessage.ts b/src/protocols/basicmessage.ts index b6ce926..14caf10 100644 --- a/src/protocols/basicmessage.ts +++ b/src/protocols/basicmessage.ts @@ -1,5 +1,8 @@ import {logger} from "../logging"; import { sendMessage, pack } from "../didcommv2"; +import { getChatItem, MessageType,importContact,getAllChats,sendMessages } from '../roots' +import * as contact from '../relationships' +import { constants } from "buffer"; export async function sendBasicMessage(content: string, from: string, to: string) { try { @@ -24,6 +27,24 @@ export async function sendBasicMessage(content: string, from: string, to: string export async function receiveBasicMessage(msg: any) { const content = JSON.parse(msg.message).body.content + const relName = JSON.parse(msg.message).body.displayName + const from = msg.from + console.log('from basic message,', from) + console.log('relName basic message,', relName) + let chat = await getChatItem(relName) + + //if chat is undefined, create a new chat + if (typeof chat === 'undefined') { + await importContact({ + displayName: relName, + displayPictureUrl: contact.prismLogo, + did: from + }) + } + chat = await getChatItem(relName) + logger('chatssssss', chat) + const msgs = await sendMessages(chat, [content], 'textMsgType', 'RootsHelper') + logger("Basic Message received:", content) return content } \ No newline at end of file diff --git a/src/protocols/pickup.ts b/src/protocols/pickup.ts index 4a3fb76..d22b180 100644 --- a/src/protocols/pickup.ts +++ b/src/protocols/pickup.ts @@ -1,15 +1,18 @@ import {logger} from "../logging"; -import { sendMessage, pack, receiveMessage } from "../didcommv2"; - -export async function retrieveMessages(from: string, to: string){ +import { sendMessage, pack, receiveMessage, unpack } from "../didcommv2"; +export async function retrieveMessages(from: string, to: string) { try { const messageCount = await statusRequest(from, to) logger("Pickup message count: "+messageCount) + //create empty array Typescript + let messages: { type: string; body: string; }[] = [] + if (messageCount>0){ const attachments = await deliveryRequest(1,from, to) - await processDelivery(attachments, from, to) - } - return messageCount + logger("Pickup attachments: "+attachments[0].data.json) + messages = await processDelivery(attachments, from, to) + } + return [messageCount,messages] } catch (error: any) { logger("pickup - Error", error) } @@ -71,17 +74,29 @@ export async function messageReceived(ids: string[], from: string, to: string) { async function processDelivery(attachments: any[], from: string, to: string) { try { - attachments.forEach(async function (attachment) { + let messages: { type: any; body: any; }[] = [] + for (const attachment of attachments) { const msgPacked = attachment.data.json const msgId = attachment.id await messageReceived([msgId], from, to) + //log msgPacked to console + logger("Pickup msgId: "+msgId) receiveMessage(JSON.stringify(msgPacked)) - }) + const msg = await unpackReceivedMessage(JSON.stringify(msgPacked)) + logger("Pickupedd msg type: "+msg.type) + messages.push(msg) + } + return messages } catch (error: any) { logger("pickup - Error", error) } } +export async function unpackReceivedMessage(packMsg: any) { + const unpacked = await unpack(packMsg) + const msg = JSON.parse(unpacked.message) + return {type: msg.type, body: msg.body} +} export async function receivePickup(msg: any) { try { const type = JSON.parse(msg.message).type diff --git a/src/roots/index.ts b/src/roots/index.ts index fd00091..3676fb0 100644 --- a/src/roots/index.ts +++ b/src/roots/index.ts @@ -27,7 +27,8 @@ export enum MessageType { MEDIATOR_REQUEST_MEDIATE = "mediatorRequestMediate", MEDIATOR_KEYLYST_UPDATE = "mediatorKeyListUpdate", MEDIATOR_STATUS_REQUEST = "mediatorStatusReuqest", - SHOW_QR_CODE = "showQRCode" + SHOW_QR_CODE = "showQRCode", + MEDIATOR_QUERY_PROTOCOLS = "mediatorQueryProtocol2" } //meaningful literals @@ -449,7 +450,7 @@ export function getChatItem(chatAlias: string) { } //TODO make order of chats deterministic (likely should be most recent first) -function getChatItems() { +export function getChatItems() { logger("roots - getting chat items") const chatItemJsonArray = store.getItems(allChatsRegex) logger("roots - got chat items", String(chatItemJsonArray)) diff --git a/src/roots/peerConversation.ts b/src/roots/peerConversation.ts index 52ba63a..72c02f3 100644 --- a/src/roots/peerConversation.ts +++ b/src/roots/peerConversation.ts @@ -1,11 +1,12 @@ import { getChatItem, sendMessage, MessageType } from "." -import { createDIDPeer} from '../didpeer' +import { createDIDPeer,resolveDIDPeer} from '../didpeer' import * as store from '../store' import * as models from '../models' import * as contact from '../relationships' import { decodeOOBURL, generateOOBURL, sendBasicMessage, mediateRequest, keylistUpdate, retrieveMessages, shortenURLRequest, discoverFeatures } from '../protocols'; +import { logger } from "../logging" @@ -18,35 +19,44 @@ export async function startConversation(chatId: string) { if (toDid.startsWith("did:peer")) { // Create a dedicated DID Peer and update chat const fromDid = await createDIDPeer(null,null) - chat.fromDids = [fromDid] - console.log(chat) - - // Discover Peer features - const features = await discoverFeatures(fromDid, toDid) - console.log(features) - chat.feautures = features - await store.updateItem(models.getStorageKey(chatId, models.ModelType.CHAT), JSON.stringify(chat)) - await sendMessage(chat, - chat.title + " supports the following protocols:", - MessageType.TEXT, contact.ROOTS_BOT) - var isMediator = false - for (const feat of features) { - if (feat.id.includes("coordinate-mediation/2.0")) {isMediator = true} + const DidDoc = await resolveDIDPeer(toDid) + const serviceEndpoint = DidDoc.service[0].serviceEndpoint + logger('DidDoc for sender ', DidDoc) + if (serviceEndpoint.startsWith("https")) { + chat.fromDids = [fromDid] + console.log(chat) + + // Discover Peer features + const features = await discoverFeatures(fromDid, toDid) + chat.feautures = features + await store.updateItem(models.getStorageKey(chatId, models.ModelType.CHAT), JSON.stringify(chat)) await sendMessage(chat, - feat.id.replace("https://didcomm.org/",""), - MessageType.TEXT, contact.ROOTS_BOT) - } - // Ask to request mediate - if (isMediator) { + chat.title + " supports the following protocols:", + MessageType.TEXT, contact.ROOTS_BOT) + var isMediator = false + for (const feat of features) { + if (feat.id.includes("coordinate-mediation/2.0")) {isMediator = true} + await sendMessage(chat, + feat.id.replace("https://didcomm.org/",""), + MessageType.TEXT, contact.ROOTS_BOT) + } + // Ask to request mediate + if (isMediator) { + + await sendMessage(chat, + "Request Mediate?", + MessageType.MEDIATOR_REQUEST_MEDIATE, contact.ROOTS_BOT) + + } + } + else{ await sendMessage(chat, - "Request Mediate?", - MessageType.MEDIATOR_REQUEST_MEDIATE, contact.ROOTS_BOT) - + "This peer is not reachable via https", + MessageType.TEXT, contact.ROOTS_BOT) } - } } @@ -87,7 +97,6 @@ export async function sendBasicMsg(chatId: string, msg: string) { const fromDid = chat.fromDids[0] const resp = await sendBasicMessage(msg, fromDid, toDid) - console.log("RM RESP: "+resp) await sendMessage(chat, resp, MessageType.TEXT, contact.ROOTS_BOT) @@ -123,10 +132,23 @@ export async function checkMessages(chatId: string) { const chat = getChatItem(chatId) const toDid = chat.toDids[0] const fromDid = chat.fromDids[0] - const resp = await retrieveMessages(fromDid, toDid) + + const [resp,messages] = await retrieveMessages(fromDid, toDid) + //Check if resp is > 0 and if so, send messages + if (messages.length > 0) { + for (const msg of messages) { + await sendMessage(chat, + "LOG:"+ '\n'+ + "type: "+msg.type.replace("https://didcomm.org/","") + '\n' + + "body: "+msg.body.content + '\n' + + "from: "+msg.body.displayName, + MessageType.TEXT , contact.ROOTS_BOT) + + } + } else { await sendMessage(chat, "Messages: " + resp, MessageType.TEXT, contact.ROOTS_BOT) - + } } \ No newline at end of file diff --git a/src/screens/RelationshipsScreen.js b/src/screens/RelationshipsScreen.js index 3e704a6..3a6f4b4 100644 --- a/src/screens/RelationshipsScreen.js +++ b/src/screens/RelationshipsScreen.js @@ -7,12 +7,16 @@ import { PRISM_BOT, ROOTS_BOT, hasNewRels } from '../relationships' import {styles} from "../styles/styles"; - +import {checkMessages} from '../roots/peerConversation' +import { getChatItems } from '../roots'; const RelationshipsScreen = ({route, navigation}) => { console.log("rel screen - params", route.params) const [refresh, setRefresh] = useState(true) const [contacts, setContacts] = useState([]) + + + useEffect(() => { addRefreshTrigger(() => { console.log("contacts screen - toggling refresh") @@ -25,6 +29,22 @@ const RelationshipsScreen = ({route, navigation}) => { hasNewRels() }, []) + //evert 6 seconds, gets all chats, finds the mediator and does a checkMessages + useEffect(() => { + const interval = setInterval(async () => { + const result = getChatItems() + for (let i =0; i < result.length; i++ ) { + let res = result[i] + if (res.id == 'Mediator') { + console.log("checking messages for mediator") + await checkMessages(res.id) + } + }; + }, 6000); + return () => clearInterval(interval); + }, []); + + return ( diff --git a/src/screens/ScanQRCodeScreen.tsx b/src/screens/ScanQRCodeScreen.tsx index a422dea..722425e 100644 --- a/src/screens/ScanQRCodeScreen.tsx +++ b/src/screens/ScanQRCodeScreen.tsx @@ -11,12 +11,13 @@ import {IconButton, Title} from 'react-native-paper'; import {BarCodeScanner} from 'expo-barcode-scanner'; import {getDemoCred} from "../credentials"; import {brandLogo, getDemoRel, getUserId} from '../relationships'; -import {getDid, importContact, importVerifiedCredential, isDemo} from '../roots' +import {getDid, importContact, importVerifiedCredential, isDemo, setDemo} from '../roots' import React from 'react'; import {CompositeScreenProps} from "@react-navigation/core/src/types"; import {BarCodeEvent} from "expo-barcode-scanner/src/BarCodeScanner"; import {styles} from "../styles/styles"; import { decodeOOBURL } from '../protocols'; +const OOB_URL = 'https://mediator.rootsid.cloud/?_oob=eyJ0eXBlIjoiaHR0cHM6Ly9kaWRjb21tLm9yZy9vdXQtb2YtYmFuZC8yLjAvaW52aXRhdGlvbiIsImlkIjoiYTJmYzI4NjMtZjhjNi00N2Y5LWEzZDMtODg3MWNlNzA0YmFiIiwiZnJvbSI6ImRpZDpwZWVyOjIuRXo2TFNvN2dyZUFRNEdaUnVwYXJRQzFjeXN4dWJjQ0ZqVlZaZHN2RFNvY0VrTDk3MS5WejZNa3RpRmg3aDNqSGNIdHhvU1dDTmoxb0I1WVJzVGdvWDhTbkRvOUhCWm1kUmR4LlNleUpwWkNJNkltNWxkeTFwWkNJc0luUWlPaUprYlNJc0luTWlPaUpvZEhSd2N6b3ZMMjFsWkdsaGRHOXlMbkp2YjNSemFXUXVZMnh2ZFdRaUxDSmhJanBiSW1ScFpHTnZiVzB2ZGpJaVhYMCIsImJvZHkiOnsiZ29hbF9jb2RlIjoicmVxdWVzdC1tZWRpYXRlIiwiZ29hbCI6IlJlcXVlc3RNZWRpYXRlIiwiYWNjZXB0IjpbImRpZGNvbW0vdjIiLCJkaWRjb21tL2FpcDI7ZW52PXJmYzU4NyJdfX0' export default function ScanQRCodeScreen({route, navigation}: CompositeScreenProps) { @@ -26,6 +27,49 @@ export default function ScanQRCodeScreen({route, navigation}: CompositeScreenPro const [timeOutId, setTimeOutId] = useState(); const modelType = route.params.type + const handleMediatorDemo = async () => { + if (!scanned && isDemo()) { + let data = OOB_URL + if (data.startsWith("http") || data.startsWith("ws")){ + if (data.toLowerCase().includes("_oobid")){ + const response = await fetch(data); + data = response.url + } + if (data.toLowerCase().includes("_oob")){ + setDemo(false) + console.log("Scan QR - OOB URL= " + data) + const decodedMsg = await decodeOOBURL(data); + //const jsonData = JSON.parse(decodedMsg) + console.log(decodedMsg) + const personLogo = require('../assets/smallBWPerson.png'); + await importContact({ + displayName: "Mediator", + displayPictureUrl: personLogo, + did: decodedMsg.from, + }) + } + } else { + // TODO HANDLE JSON ERROR + const jsonData = JSON.parse(data) + if (modelType == "credential") { + console.log("Scan QR - Importing scanned vc",jsonData) + await importVerifiedCredential(jsonData) + } else if (modelType == "contact") { + console.log("Scan QR - Importing scanned contact",jsonData) + await importContact(jsonData) + } + } + + + + } + + + + + + clearAndGoBack() + } const handleDemo = async () => { if (!scanned && isDemo()) { setScanned(true) @@ -54,7 +98,7 @@ export default function ScanQRCodeScreen({route, navigation}: CompositeScreenPro const {status} = await BarCodeScanner.requestPermissionsAsync(); setHasPermission(status === 'granted'); if (isDemo()) { - setTimeOutId(setTimeout(handleDemo, 10000)); + setTimeOutId(setTimeout(handleMediatorDemo, 5000)); } }