LaunchDarkly Bootstrapping: (JS) Property Assignment Expected - javascript

I am setting up LaunchDarkly to control my first feature flag and its working fine from server & client side.
Now I am trying LaunchDarkly Bootstrap approach (From the below given Link) and tried like below my code, but it's not accepting the double braces and I do not know How to get flag value by using the bootstrap approach, so where I did go wrong in my code?. Could anyone please help me with an example?
Link,
https://docs.launchdarkly.com/docs/js-sdk-reference#section-bootstrapping
Initialized client with Bootstrap option as below,
client = LDClient.initialize(sdkKey, userContext.user, options = {
bootstrap: {
{{ ldclient.all_flags(userContext.user) }}
}
});
And my function to get the flag value,
isFeatureEnabled: function (featureFlag, properties) {
console.log("Before Variation");
//we shall update the custom properties into user context.
if (properties) {
for (var k in properties) {
userContext.user.custom[k] = properties[k];
}
}
//later make the identity call to update the user details.
client.identify(userContext.user, null, function () { /*rules updated*/
console.log("New user's flags available");
//validate the feature flag
var showFeature = client.variation(featureFlag);
if (!showFeature) {
window.in8.platform.showUnauthorized('');
}
console.log("after Variation");
});
}

Full disclosure, My name is John, and I am part of the support team here at LaunchDarkly. I'll be happy to help you out with this problem
Firstly, it appears you are using an older version of the bootstrapping example. The new example has a typo fix, and uses the new all_flags_state method.
I see two major issues here. There is the primary issue of how to bootstrap flag variations from the back-end to the front-end, and how to appropriately utilize LaunchDarkly when using bootstrapping. I will tackle the issue of how to bootstrap flag variations from the back-end first.
The example in LaunchDarkly's documentation utilizes templating to include the bootstrapped values to the front end. Templating is a strategy for including programmatically generated content in your static source or text files. Templating is commonly used when compiling or deploying code, or at runtime when serving content to clients. This is done to render information only available at that time in the final version.
Different templating languages behave in different ways, but generally speaking you include tokens in your source or text files which direct the template renderer to replace that token with data you supply it.
In the documentation it mentions that this example is for templating using Ruby, but the example is using Mustache rendering, and Mustache is available in many different languages. Templating is a strategy for including programmatically generated content in your static source or text files. This is commonly used when compiling or deploying code, or at runtime when serving content to clients. This is done to render information only available at that time in the final version.
The example may not work depending on which back-end language and framework you are using. According to the tags associated with your question, I feel safe to assume that you are using .NET to power your back-end, which doesn't have a prescribed templating language. There are many open source solutions out there, though.
In the following example I'm going to use https://github.com/rexm/Handlebars.Net to render the a users bootstrapped flag values into the result variable. I am going to borrow code available from the example in the handle bars repo, and from LaunchDarkly's hello-bootstrap and hello-dotnet repos, which are available here: https://github.com/launchdarkly/hello-bootstrap & https://github.com/launchdarkly/hello-dotnet
string source =
#"
<html>
<head>
<script src=""https://app.launchdarkly.com/snippet/ldclient.min.js""></script>
<script>
window.ldBootstrap={{ldBootstrap}};
window.ldClientsideId=""{{ldClientsideId}}"";
window.ldUser={{ldUser}};
</script>
</head>
<body>
<h1>LaunchDarkly server-side bootstrap example</h1>
<ul>
<li><code>normal client</code>: <span class=""normal"">initializing…</span></li>
<li><code>bootstrapped client</code>: <span class=""bootstrap"">initializing…</span></li>
</ul>
<script>
var user = window.ldUser;
console.log(`Clients initialized`);
var client = LDClient.initialize(window.ldClientsideId, user);
var bootstrapClient = LDClient.initialize(window.ldClientsideId, user, {
bootstrap: window.ldBootstrap
});
client.on('ready', handleUpdateNormalClient);
client.on('change', handleUpdateNormalClient);
bootstrapClient.on('ready', handleUpdateBootstrapClient);
bootstrapClient.on('change', handleUpdateBootstrapClient);
function handleUpdateNormalClient(){
console.log(`Normal SDK updated`);
render('.normal', client);
}
function handleUpdateBootstrapClient(){
console.log(`Bootstrapped SDK updated`);
render('.bootstrap', bootstrapClient);
}
function render(selector, targetClient) {
document.querySelector(selector).innerHTML = JSON.stringify(targetClient.allFlags(user), null, 2);
}
</script>
</body>
</html>";
var template = Handlebars.Compile(source);
Configuration ldConfig = LaunchDarkly.Client.Configuration.Default("YOUR_SDK_KEY");
LdClient client = new LdClient(ldConfig);
User user = User.WithKey("bob#example.com")
.AndFirstName("Bob")
.AndLastName("Loblaw")
.AndCustomAttribute("groups", "beta_testers");
var data = new {
ldBootstrap: JsonConvert.SerializeObject(client.AllFlagsState(user)),
ldUser = JsonConvert.SerializeObject(user),
ldClientsideId = "YOUR_CLIENT_SIDE_ID"
};
var result = template(data);
You could take this example and adapt it to render your static source code when serving the page to your users.
The second issue is how you are utilizing the SDK. I see that you are calling identify before evaluating your user every time. Each time you call identify the SDK needs to reinitialize. This means that even after bootstrapping your initial variations you will force the SDK to reinitialize by calling identify, removing all benefits of bootstrapping. As a solution, detect if your user object has changed. if it has, then call identify. Otherwise, do not call identify so that the SDK uses the cached user attributes.
If you want to dive deeper into this and provide us with some more of the source for your wrapper you can reach out to us at support#launchdarkly.com

Related

How do you include a set with a relative path in a SAP hybrid app?

I've made an app in SAP UI5 that works in online mode when using a browser, and offline mode when using a mobile device. I'm trying to display some options in a popup that are fetched from a set. The problem is that the set is found when I run it in online mode, but not offline.
The set is an extension of another set, and depends upon a variable, e.g. /FooSet('P1')/Types, where P1 is a variable.
The implementation for fetching the items from the set and displaying them in the popup is the following:
this._popup.getAggregation('_dialog').getContent()[1].bindAggregation("items", {
path: "/FooSet('" + varType + "')/Types",
template: new sap.m.StandardListItem({
title: "{Title}",
description: "{Desc}"
});
As mentioned, this works fine online, but the Types set is empty when running it offline.
I suspect that the problem lies in the definingRequests.json file, which contains all the sets that are to be included in the offline app. Here's a snippet:
{
"definingRequests": {
"FooSet": "/FooSet",
"BarSet": "/BarSet",
"ZooSet": "/ZooSet"
}
}
Here, the three sets are included; I'm getting the correct data from FooSet, for example, which contains the different variables like P1, P2, P3 and so on. So my question is: How do I include the Types set from /FooSet('P1')/Types when there's a variable like P1 involved?
I've already tried defining it like "Types": "/Types", as well as "Types": "/FooSet/Types", but that's not working neither.
Thanks in advance!
As suspected, I was just defining the set incorrectly in definingRequests.json.
It was supposed to be "TypesSet": "/TypesSet", not "Types": "/Types", even though the path is named Types. All is good now :)

Error when running Youtube Data Service in App Scripts (js) – Daily Limit for Unauthenticated Use Exceeded

I'm running a custom function in App Scripts which utilizes the Youtube (YouTube Data API v3) advanced service. When running, I get the following error:
GoogleJsonResponseException: API call to youtube.videos.list failed with error: Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup. (line 15).
I'm not sure how to authenticate my application. I've added it to a cloud project and enabled the API's.
Update: Here's what my code looks like:
function getYoutubeData(youtubeId) {
// Don't run on empty
if(!youtubeId){return null}
// Make the request
var vidData = YouTube.Videos.list("statistics, snippet", {id: youtubeId}).items;
if (!vidData|vidData.length<1){return null}
// Get the first item
vidData = vidData[0];
return vidData.statistics
}
I believe your goal as follows.
You want to put the value of vidData.statistics in your script to the cell.
You want to achieve this using custom function like =getYoutubeData(youtubeId).
For this, how about this answer?
Issue and workaround:
Unfortunately, when YouTube Data API of Advanced Google services is used in the custom function, the access token is not used. From your script, I think that the reason of your issue is this. For example, when the function of const sample = () => ScriptApp.getOAuthToken(); is used as the custom function like =sample(), no value is returned. I think that this is the current specification of Google side because of the security.
In order to achieve your goal under above situation, how about the following workarounds?
Workaround 1:
In this workaround, at first, the youtube ID is set to the cells in Google Spreadsheet. And the value of vidData.statistics are retrieved by the Google Apps Script which is not the custom function and replace the youtube ID with the result values.
Sample script:
Please set the range of cells of youtube IDs to sourceRange and the sheet name. At the sample, it supposes that the youtube IDs are put to the cells "A1:A10". And please run getYoutubeData() at the script editor. Of course, you can also set this to the custom menu.
function getYoutubeData() {
const sourceRange = "A1:A10"; // Please set the range of cells of youtube IDs.
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); // Please set the sheet name.
const range = sheet.getRange(sourceRange);
const youtubeIds = range.getValues();
const values = youtubeIds.map(([youtubeId]) => {
// This is your script.
if(!youtubeId){return [null]}
var vidData = YouTube.Videos.list("statistics, snippet", {id: youtubeId}).items;
if (!vidData|vidData.length<1){return [null]}
vidData = vidData[0];
return [JSON.stringify(vidData.statistics)];
});
range.setValues(values);
}
Workaround 2:
In this workaround, the custom function is used. But, in this case, the Web Apps is used as the wrapper. By this, the authorization process is done at the Web Apps. So the custom function can be run without the authorization. Please do the following flow.
1. Prepare script.
When your script is used, it becomes as follows. Please copy and paste the following script to the script editor.
Sample script:
// This is your script.
function getYoutubeData_forWebApps(youtubeId) {
// Don't run on empty
if(!youtubeId){return null}
// Make the request
var vidData = YouTube.Videos.list("statistics, snippet", {id: youtubeId}).items;
if (!vidData|vidData.length<1){return null}
// Get the first item
vidData = vidData[0];
return vidData.statistics
}
// Web Apps using as the wrapper.
function doGet(e) {
const res = getYoutubeData_forWebApps(e.parameter.youtubeId)
return ContentService.createTextOutput(JSON.stringify(res));
}
// This is used as the custom function.
function getYoutubeData(youtubeId) {
const url = "https://script.google.com/macros/s/###/exec?youtubeId=" + youtubeId; // Please set the URL of Web Apps after you set the Web Apps.
return UrlFetchApp.fetch(url).getContentText();
}
2. Deploy Web Apps.
On the script editor, Open a dialog box by "Publish" -> "Deploy as web app".
Select "Me" for "Execute the app as:".
By this, the script is run as the owner.
Select "Anyone, even anonymous" for "Who has access to the app:".
In this case, no access token is required to be request. I think that I recommend this setting for testing this workaround.
Of course, you can also use the access token. But, in this case, when the access token is used, this sample script cannot be directly used as the custom function.
Click "Deploy" button as new "Project version".
Automatically open a dialog box of "Authorization required".
Click "Review Permissions".
Select own account.
Click "Advanced" at "This app isn't verified".
Click "Go to ### project name ###(unsafe)"
Click "Allow" button.
Click "OK".
Copy the URL of Web Apps. It's like https://script.google.com/macros/s/###/exec.
When you modified the Google Apps Script, please redeploy as new version. By this, the modified script is reflected to Web Apps. Please be careful this.
Please set the URL of https://script.google.com/macros/s/###/exec to url of above script. And please redeploy Web Apps. By this, the latest script is reflected to the Web Apps. So please be careful this.
4. Test this workaround.
Please put =getYoutubeData("###youtubeId###") to a cell. By this, the youtube ID is sent to the Web Apps and the Web Apps returns the values of vidData.statistics.
Note:
These are the simple sample scripts for explaining the workarounds. So when you use this, please modify it for your actual situation.
References:
Custom Functions in Google Sheets
Web Apps
Taking advantage of Web Apps with Google Apps Script

How to use JavaScript or/and PHP, to detect a website/page being stolen/cloned and then redirect reader back to my website

I found hundreds of cloned versions of my website.
Whoever is doing that are using some code that clones my web pages, changes my website name mydomain.com to clone1.com, clone2.com, clone3.com etc and this makes it impossible to use a simple JS or PHP to check if the header URL is = to mysite.com then redirect.
It also does not work using the .htaccess
For this reason I have created this code:
<script type="text/javascript">
if (window.location.href== "http://clone1.com/cat1/{{{ $title->id }}}-{{ (Str::slug($title->title)) }}/cat2/{{ $se->n }}/cat3/{{ $episode->ep_n }}")
{
window.location.href = 'http://google.com/';
}
</script>
This script completes its purpose but is too long and is also very restrictive because it must contain the exact URL.
I'm looking to do this:
<script type="text/javascript">
if (window.location.href== "http://
//contains this part in its URL
clone1.com , clone2.com , clone3.com , clone4....
}}")
{
window.location.href = 'http://google.com/';
}
</script>
How can I create a global JS (JavaScript), that would detect if the current page is not on my domain and then redirect the reader to my domain and the same page?
Many thanks
1. Best Solution - Early Detection
Depending on your main traffic source, it is possible to detect who is scrapping you and block them based on their IP, Headers, number of page views and other data, using PHP & HTACCESS.
I really like this answer on the StackOverflow, that discusses almost all the options available for early detection.
How to detect fake users ( crawlers ) and cURL
2. Plugins & Extensions for Open Source Content Management Systems
Wordpress
If using Wordpress CMS, you can try some plugins, like WordFence, that can detect and block fake Google Crawlers, block based on the number of page views etc.
Other CMS
If you can't find a similar solution for your CMS of choice, consider to ask a community for a help with creating the solution like that, as I believe many people could benefit from it.
3. Solution for already stolen content with JavaScript
Sometimes the easiest road to hide something in JS, is to actually HIDE something by OBFUSCATING and by hiding in multiple important files. For example, obfuscate some important file on your website without which the website just wouldn't work properly.
For example, put an obfuscated version of the code below somewhere in JS file in the header, Obfuscate this code using any free services online or download your own library on Github:
Non-Obfuscated:
w='mysite.com'; // Current URL e.g. 'mysite.com/category1/page2/'
function check_origin(){
var check = 587;
if(window.location.hostname != w){
window.location.href = w;
}
return check;
}
var check = check_origin();
Obfuscated example:
var _0x303e=["\x6D\x79\x73\x69\x74\x65\x2E\x63\x6F\x6D","\x68\x6F\x73\x74\x6E\x61\x6D\x65","\x6C\x6F\x63\x61\x74\x69\x6F\x6E","\x68\x72\x65\x66"];w= _0x303e[0];function check_origin(){var check=587;if(window[_0x303e[2]][_0x303e[1]]!= w){window[_0x303e[2]][_0x303e[3]]= w};return check}var check=check_origin()
Now put an additional code in some Footer JS File, to verify the code above wasn't modified in any way:
Non-Obfuscated example:
if(w!=='mysite.com'||check == false || typeof check == 'undefined' || check !== 587 ){
window.location.href = 'mysite.com';
}
Obfuscated:
var _0x92bb=["\x6D\x79\x73\x69\x74\x65\x2E\x63\x6F\x6D","\x75\x6E\x64\x65\x66\x69\x6E\x65\x64","\x68\x72\x65\x66","\x6C\x6F\x63\x61\x74\x69\x6F\x6E"];if(w!== _0x92bb[0]|| check== false|| typeof check== _0x92bb[1]|| check!== 587){window[_0x92bb[3]][_0x92bb[2]]= _0x92bb[0]}
I have used free online service from Google's search results for the term "Free Online JS Obfuscator:
https://javascriptobfuscator.com/Javascript-Obfuscator.aspx
4. Fight thieves with available methods e.g. Request a Ban from Search Engines – The Digital Millennium Copyright Act of 1998
Here is a blog-post that describes what to do when someone is stealing your content.
https://lorelle.wordpress.com/2006/04/10/what-do-you-do-when-someone-steals-your-content/
You can investigate who is doing that and report them to their partners, search engines, advertisers - to disrupt their business.
Depending on their country of origin and yours, it is maybe even possible to sue them and win.
why not check if hostname is your ?
if(window.location.hostname != 'mysite.com'){
window.location.href = 'http://google.com/';
}

Enable users of a WebRtc app to download webrtc logs via javascript

I've seen the following:
chrome://webrtc-internals
However I'm looking for a way to let users click a button from within the web app to either download or - preferably - POST WebRtc logs to an endpoint baked into the app. The idea is that I can enable non-technical users to share technical logs with me through the click of a UI button.
How can this be achieved?
Note: This should not be dependent on Chrome; Chromium will also be used as the app will be wrapped up in Electron.
You need to write a javascript equivalent that captures all RTCPeerConnection API calls. rtcstats.js does that but sends all data to a server. If you replace that behaviour with storing it in memory you should be good.
This is what I ended up using (replace knockout with underscore or whatever):
connectionReport.signalingState = connection.signalingState;
connectionReport.stats = [];
connection.getStats(function (stats) {
const reportCollection = stats.result();
ko.utils.arrayForEach(reportCollection, function (innerReport) {
const statReport = {};
statReport.id = innerReport.id;
statReport.type = innerReport.type;
const keys = innerReport.names();
ko.utils.arrayForEach(keys, function (reportKey) {
statReport[reportKey] = innerReport.stat(reportKey);
})
connectionReport.stats.push(statReport);
});
connectionStats.push(connectionReport);
});
UPDATE:
It appears that this getStats mechanism is soon-to-be-deprecated.
Reading through js source of chrome://webrtc-internals, I noticed that the web page is using a method called chrome.send() to send messages like chrome.send('enableEventLogRecordings');, to execute logging commands.
According to here:
chrome.send() is a private function only available to internal chrome
pages.
so the function is sandboxed which makes accessing to it not possible

Using API Key to generate chart for external site but showing login screen

I'm trying to create a burndown chart on a webapp and using the loginkey example code, but switched loginkey to apikey (code below). My API Key is placed where it says CorrectAPIKeyHere, and actual id's for workspace_id and project_id. I have double checked to make sure it's the correct key. Here's what shows up: http://pasteboard.co/P3WXWgPk.png
However, the code works if I'm already logged into Rally. Is there anything I'm missing from my code?
<script type="text/javascript" src="https://rally1.rallydev.com/apps/1.26/sdk.js?apiKey=CorrectAPIKeyHere"></script>
<script type="text/javascript" src="https://rally1.rallydev.com/apps/1.26/sdk.js"></script>
<script type="text/javascript">
function initPage() {
console.log(gon.project_oid);
var rallyDataSource = new rally.sdk.data.RallyDataSource("workspace_id", project_id,"true","false");
console.log($(main_content).width());
var config = {
report: rally.sdk.ui.StandardReport.IterationBurndown,
height: 400,
iterations: iteration_id
};
var report = new rally.sdk.ui.StandardReport(config);
report.display("burndown_chart");
}
rally.addOnLoad(initPage);
</script>
Unfortunately there are a couple different things contributing to your current bad times. API Keys are not supported in App SDK 1.x. They are also not supported by the Analytics1 service which backs that StandardReport component.
So the only way forward is to go back to using LoginKey, which comes with the usual caveats about security, etc. Did you have a working app with LoginKey?
Good news! Api Keys are fully supported now in App SDK 2.1 and the StandardReport component so it should be totally possible to do this now.
Some useful links:
Embedding apps externally:
https://help.rallydev.com/apps/2.1/doc/#!/guide/embedding_apps
The StandardReport component:
https://help.rallydev.com/apps/2.1/doc/#!/api/Rally.ui.report.StandardReport

Categories

Resources