Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
elv-kevin committed May 30, 2024
2 parents f5b901c + 080abdc commit 03181be
Show file tree
Hide file tree
Showing 13 changed files with 349 additions and 166 deletions.
6 changes: 6 additions & 0 deletions SampleTestConfiguration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"config-url": "https://demov3.net955210.contentfabric.io/config",
"tenant-contract-id": "itenXXX",
"eth-url": "",
"fabric-url": "",
}
2 changes: 1 addition & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ <h2>Playing Video from the Fabric</h2>
<p>See the <a href="https://github.com/eluv-io/elv-stream-sample">Stream Sample App</a> for a detailed explanation on playing video from the Fabric using the Eluvio JavaScript client.</p>
<p><a name="abr-publishing"></a></p>
<h2>Publishing ABR Video Content on the Fabric</h2>
<p>For more information on how to publish ABR content see <a href="https://eluv-io.github.io/elv-client-js/abr/index.html">this detailed guide</a>.</p>
<p>For more information on how to publish ABR content see <a href="https://docs.eluv.io/docs/guides/media-ingest/">this detailed guide</a>.</p>
<p><a name="resources"></a></p>
<h2>Other Resources</h2>
<p>Our Core, Fabric Browser and Video Editor apps are all completely open source, and make extensive use of this client:</p>
Expand Down
161 changes: 80 additions & 81 deletions src/ElvClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ const Pako = require("pako");
const {
ValidatePresence
} = require("./Validation");
const CBOR = require("cbor-x");
const UrlJoin = require("url-join");

const networks = {
"main": "https://main.net955305.contentfabric.io",
"demo": "https://demov3.net955210.contentfabric.io",
"demov3": "https://demov3.net955210.contentfabric.io",
"local": "http://127.0.0.1:8008/config?qspace=dev&self",
"test": "https://test.net955203.contentfabric.io"
};

Expand Down Expand Up @@ -134,7 +135,7 @@ class ElvClient {
* @param {Array<string>=} searchURIs - A list of full URIs to search service endpoints
* @param {number=} ethereumContractTimeout=10 - Number of seconds to wait for contract calls
* @param {string=} trustAuthorityId - (OAuth) The ID of the trust authority to use for OAuth authentication
* @param {string=} staticToken - Static token that will be used for all authorization in place of normal auth
* @param {string=} staticToken - Static token that will be used for all authorization in place of normal auth. Also known as an anonymous token containing the space
* @param {boolean=} noCache=false - If enabled, blockchain transactions will not be cached
* @param {boolean=} noAuth=false - If enabled, blockchain authorization will not be performed
* @param {boolean=} assumeV3=false - If enabled, V3 fabric will be assumed
Expand Down Expand Up @@ -274,6 +275,17 @@ class ElvClient {
}
}

/**
* Return a list of valid Eluvio Content Fabric network names and their associated configuration URLs
*
* @methodGroup Miscellaneous
*
* @return {Object} - An object using network names as keys and configuration URLs as values.
*/
static Networks() {
return networks;
}

/**
* Create a new ElvClient for the specified network
*
Expand Down Expand Up @@ -574,78 +586,65 @@ class ElvClient {
* @param {string=} matchEndpoint - Return node(s) matching the specified endpoint
* @param {string=} matchNodeId - Return node(s) matching the specified node ID
*
* @return {Array<Object>} - A list of nodes in the space matching the parameters
* @return {Promise<Array<Object>>} - A list of nodes in the space matching the parameters
*/
async SpaceNodes({matchEndpoint, matchNodeId}={}) {
let bign = await this.CallContractMethod({
contractAddress: this.contentSpaceAddress,
methodName: "numActiveNodes",
});
let n = bign.toNumber();

return (await Utils.LimitedMap(
5,
[...new Array(n)],
async (_, index) => {
let bigi = Ethers.BigNumber.from(index);
let addr = await this.CallContractMethod({
contractAddress: this.contentSpaceAddress,
methodName: "activeNodeAddresses",
methodArgs: [bigi],
formatArguments: true
});

let nodeId = this.utils.AddressToNodeId(addr);

if(matchNodeId && nodeId !== matchNodeId) {
return;
}

let locatorsHex = await this.CallContractMethod({
contractAddress: this.contentSpaceAddress,
methodName: "activeNodeLocators",
methodArgs: [bigi]
});

let node = {id: nodeId, endpoints: []};
let nodes;
this.SetStaticToken();

if(matchEndpoint) {
({nodes} = await this.utils.ResponseToJson(
this.HttpClient.Request({
path: UrlJoin("nodes"),
method: "GET",
headers: {
Authorization: `Bearer ${this.staticToken}`
}
})
));

// Parse locators CBOR
let locators = CBOR.decodeMultiple(
Buffer.from(
locatorsHex.slice(2, locatorsHex.length),
"hex"
)
);
if(!nodes || !Array.isArray(nodes) || nodes.length === 0) {
return [];
}

return nodes.filter(node => {
let match = false;

if(locators.length >= 5) {
let fabArray = locators[4].fab;
if(fabArray) {
for(let i = 0; i < fabArray.length; i ++) {
let host = fabArray[i].host;
if(
node.services &&
node.services.fabric_api &&
node.services.fabric_api.urls
) {
const results = (node.services.fabric_api.urls || []).find(url => url.includes(matchEndpoint));

if(matchEndpoint && !matchEndpoint.includes(host)) {
continue; // Not a match
}
if(results) {
match = true;
}
}

match = true;
let endpoint = fabArray[i].scheme + "://" + host;
if(matchNodeId && node.id === matchNodeId) {
match = true;
}

if(fabArray[i].port) {
endpoint = endpoint + ":" + fabArray[i].port;
}
this.ClearStaticToken();

endpoint = endpoint + "/" + fabArray[i].path;
node.endpoints.push(endpoint);
}
return match;
});
} else if(matchNodeId) {
this.SetStaticToken();
let node = await this.utils.ResponseToJson(
this.HttpClient.Request({
path: UrlJoin("nodes", matchNodeId),
method: "GET",
headers: {
Authorization: `Bearer ${this.staticToken}`
}
}
})
);

return match ? node : undefined;
}
))
.filter(n => n);
this.ClearStaticToken();
return [node];
}
}

/**
Expand Down Expand Up @@ -991,11 +990,11 @@ class ElvClient {
* @param {string} messasge - A JSON object representing the message to sign
*/
async CreateSignedMessageJSON({
message
message
}) {

// Only one kind of signature supported currently
const type = "mje_" // JSON message, EIP192 signature
const type = "mje_"; // JSON message, EIP192 signature

const msg = JSON.stringify(message);
const signature = await this.PersonalSign({message: msg, addEthereumPrefix: true});
Expand All @@ -1020,23 +1019,23 @@ class ElvClient {
}) {
const type = signedMessage.slice(0,4);
switch(type) {
case "mje_":
const msgBytes = Utils.FromB58(signedMessage.slice(4));
const signature = msgBytes.slice(0, 65);
const msg = msgBytes.slice(65);
const obj = JSON.parse(msg);

const prefixedMsgHash = Ethers.utils.keccak256(Buffer.from(`\x19Ethereum Signed Message:\n${msg.length}${msg}`, "utf-8"));
const signerAddr = Ethers.utils.recoverAddress(prefixedMsgHash, signature);

return {
type: type,
message: obj,
signerAddress: signerAddr,
signature: "0x" + signature.toString("hex")
};
default:
throw new Error(`Bad message type: ${type}`);
case "mje_":
const msgBytes = Utils.FromB58(signedMessage.slice(4));
const signature = msgBytes.slice(0, 65);
const msg = msgBytes.slice(65);
const obj = JSON.parse(msg);

const prefixedMsgHash = Ethers.utils.keccak256(Buffer.from(`\x19Ethereum Signed Message:\n${msg.length}${msg}`, "utf-8"));
const signerAddr = Ethers.utils.recoverAddress(prefixedMsgHash, signature);

return {
type: type,
message: obj,
signerAddress: signerAddr,
signature: "0x" + signature.toString("hex")
};
default:
throw new Error(`Bad message type: ${type}`);
}
}

Expand Down
54 changes: 54 additions & 0 deletions src/RemoteSigner.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const Ethers = require("ethers");
const Utils = require("./Utils");
const HttpClient = require("./HttpClient");
const UrlJoin = require("url-join");
const UUID = require("uuid");

class RemoteSigner extends Ethers.Signer {
constructor({
Expand Down Expand Up @@ -72,6 +73,59 @@ class RemoteSigner extends Ethers.Signer {
this.signer = this.provider.getSigner(this.address);
}

async RetrieveCSAT({email, nonce, force=false}) {
nonce = nonce || Utils.B58(UUID.parse(UUID.v4()));

let response = await Utils.ResponseToJson(
this.HttpClient.Request({
method: "POST",
body: {
email,
nonce,
force
},
path: UrlJoin("as", "wlt", "sign", "csat"),
headers: {
Authorization: `Bearer ${this.authToken}`
},
})
);

response.nonce = nonce;

return response;
}

async CSATStatus({accessToken}) {
try {
const response = await Utils.ResponseToJson(
this.HttpClient.Request({
method: "POST",
path: UrlJoin("as", "wlt", "login", "status"),
headers: {
Authorization: `Bearer ${accessToken}`
},
})
);

return response && response.is_active;
} catch(error) {
return !error || error.status !== 403;
}
}

async ReleaseCSAT({accessToken}) {
return await Utils.ResponseToJson(
this.HttpClient.Request({
method: "POST",
path: UrlJoin("as", "wlt", "login", "release"),
headers: {
Authorization: `Bearer ${accessToken}`
},
})
);
}

// Overrides

getAddress() {
Expand Down
8 changes: 4 additions & 4 deletions src/client/ContentAccess.js
Original file line number Diff line number Diff line change
Expand Up @@ -2322,17 +2322,17 @@ exports.EmbedUrl = async function({
break;
case "useTicketCodes":
embedUrl.searchParams.set("ptk", "");
if (options.tenantId) {
if(options.tenantId) {
embedUrl.searchParams.set("ten", options.tenantId);
}
if (options.ntpId) {
if(options.ntpId) {
embedUrl.searchParams.set("ntp", options.ntpId);
}
if (options.ticketCode) {
if(options.ticketCode) {
embedUrl.searchParams.set("tk", Buffer.from(options.ticketCode).toString("base64"));

}
if (options.ticketSubject) {
if(options.ticketSubject) {
embedUrl.searchParams.set("sbj", Buffer.from(options.ticketSubject).toString("base64"));
}
break;
Expand Down
1 change: 0 additions & 1 deletion src/client/ContentManagement.js
Original file line number Diff line number Diff line change
Expand Up @@ -1068,7 +1068,6 @@ exports.PublishContentVersion = async function({objectId, versionHash, awaitComm
await new Promise(resolve => setTimeout(resolve, pollingInterval));
}
} catch(error) {
console.error(error);
if(error.status !== 404) {
throw error;
}
Expand Down
4 changes: 2 additions & 2 deletions src/client/LiveConf.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,13 @@ class LiveConf {
return seg;
}

/*
/*
* Calculate output timebase from the encoder (codec) timebase. The videoTimeBase parameter
* represents the encoder timebase. The format muxer will change it so it is greater than 10000.
*/
calcOutputTimebase(codecTimebase) {
let outputTimebase = codecTimebase;
while (outputTimebase < 10000)
while(outputTimebase < 10000)
outputTimebase = outputTimebase * 2;
return outputTimebase;
}
Expand Down
Loading

0 comments on commit 03181be

Please sign in to comment.