How do I use YUI3 in a Chrome extension? - google-chrome-extension

If I download the minified YUI3 loader and include it in my background.html I get the following error:
Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' chrome-extension-resource:".
Can YUI3 be used in an extension?

It looks like it's blocking you from using eval(). Make sure you have the following line in your manifest.
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"

This is how I was able to do it. Clone yui3 and yui3-gallery from git and in my extension tree, add the modules I need. Then load config.js from popup.html and background.html. The file looks like this:
YUI_config = {
filter: "raw",
base: "yui3/build/",
root: "yui3/build/",
comboBase: "/combo?",
combine: false,
groups: {
gallery: {
base: "yui3-gallery/build/",
root: "yui3-gallery/build/",
comboBase: "/combo?",
combine: false,
patterns: {
"gallery-": {},
"gallerycss-": { type: "css" }
}
}
}
};
Now it all works!

Related

Required module doesn't work on chrome extension script

I'm new to extension development and not good at bundlers so I'm using chrome-extension-webpack-boilerplate to start developing my extension.
I want to make a simple timer extension, so after following the bolirplate repository's instructions, I downloaded a module called tiny-timer with yarn add tiny-timer. Then changed the popup.html and popup.js (added code from the tiny-timer repo that works fine on RunKit).
manifest.json:
{
"name": "Chrome Timer Extension",
"options_page": "options.html",
"background": {
"page": "background.html"
},
"browser_action": {
"default_popup": "popup.html",
"default_icon": "icon-34.png"
},
"icons": {
"128": "icon-128.png"
},
"manifest_version": 2,
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
}
popup.js
import "../css/popup.css";
const Timer = require("tiny-timer");
console.log(Timer);
const timer = new Timer();
popup.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1 id="timer"></h1>
<button id="pause">Pause</button>
<button id="reset">Reset</button>
<button id="continue">Go</button>
</body>
</html>
Popup output:
Module
>default: class Timer
Symbol(Symbol.toStringTag): "Module"
__esModule: true
>[[Prototype]]: Object
Uncaught TypeError: Timer is not a constructor
at eval (popup.js?dffe:3)
at Module../src/js/popup.js (popup.bundle.js:1271)
at __webpack_require__ (popup.bundle.js:727)
at fn (popup.bundle.js:101)
at Object.0 (popup.bundle.js:1286)
at __webpack_require__ (popup.bundle.js:727)
at popup.bundle.js:794
at popup.bundle.js:797

Unable to play HLS m3u8 file with AWS CloudFront Signed Cookies

I am working on a project where I will need to play HLS encrypted video (.m3u8) file. I am using CloudFront and signed cookies to secure the content. I am able to play .m3u8 file without signed cookies but when I use signed cookies then cookies do not get send in requests.
I am using the alternate domain for CloudFront distribution and I confirm that apart from .m3u8 file I am able to access all other files using signed cookies.
After research, I found that if I set withCredentials to true like the following code then signed cookies will be send in request:
player.ready(function() {
player.src({
src: 'https://protected.example.com/output-plain/art.m3u8',
type: 'application/x-mpegURL',
withCredentials: true
});
});
This code works and signed cookies are getting send in request however I started getting a new error which is:
Access to XMLHttpRequest at 'https://protected.example.com/output-plain/art.m3u8undefined' from origin 'https://example.com' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
Then I found that I have to set Access-Control-Allow-Credentials to true. however, this does not work for me.
I am using video.js library, I have also tried hls.js and getting the same error and stuck at same place.
I am stuck on this issue for the last 7 days and I think AWS docs are really overwhelming, I have referred many questions on SO and issues on Github but still no luck. Hope someone will help me here.
Here is the screenshot of CloudFront distribution behavior:
And here is my php and js code; index.php:
<?php
header("Access-Control-Allow-Origin: https://protected.example.com");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Max-Age: 1000");
header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Origin, Cache-Control, Pragma, Authorization, Accept, Accept-Encoding");
header("Access-Control-Allow-Methods: PUT, POST, GET, OPTIONS, DELETE");
?>
<!DOCTYPE html>
<html>
<head>
<link href="https://vjs.zencdn.net/7.10.2/video-js.css" rel="stylesheet" />
</head>
<body>
<video
id="video_player"
class="video-js"
controls
preload="auto"
poster="//vjs.zencdn.net/v/oceans.png"
data-setup='{}'
width=600 height=300>
</video>
<script src="https://vjs.zencdn.net/7.10.2/video.js"></script>
<script>
var player = videojs('video_player')
player.responsive(true);
player.ready(function() {
player.src({
src: 'https://protected.example.com/output-plain/art.m3u8',
type: 'application/x-mpegURL',
withCredentials: true
});
});
</script>
</body>
</html>
Here is S3 bucked CORS Policy:
[
{
"AllowedHeaders": [
""
],
"AllowedMethods": [
"POST",
"GET",
"PUT",
"HEAD"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": []
}
]
Thank you in advance.
The answer is within the browser's error message, "The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'." Your S3 bucket's CORS policy cannot use a wildcard for the AllowedOrigins value.
Also your empty AllowedHeaders value may be removing the Host value from the preflight request check, so let's set it to a wildcard just to be safe.
If you update your S3 bucket's CORS policy to this, it should resolve the issue:
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"POST",
"GET",
"PUT",
"HEAD"
],
"AllowedOrigins": [
"https://example.com",
"https://protected.example.com"
],
"ExposeHeaders": []
}
]

Using bootbox in RequireJS app

I have a sample app.js file with:
requirejs.config({
"baseUrl": "js/lib",
"paths": {
"jquery": "jquery",
"app": "../app",
"bootstrap": "bootstrap/js/bootstrap.bundle",
"bootbox": "bootbox.min"
},
"shim": {
"bootstrap": {
"deps": ["jquery"],
"exports": 'bootbox'
},
"main": { "deps": ["jquery","bootstrap"] },
"bootbox": {
"deps": ["jquery","bootstrap"],
"exports": 'bootbox'
},
}
});
require(['jquery','bootstrap','bootbox'], function($){
$(function(jquery) {
bootbox.alert("bla")
});
});
When I run my page, I can see the correct JS files being grabbed:
...yet my code fails:
bootbox.alert("bla")
Gives:
ReferenceError: bootbox is not defined
I must be missing something simple (again, apologies if this is a newbie error - I'm still trying to get my head around this library)
Don't use shim with Bootbox. If you look at the source code of Bootbox, you'll see it calls define, which registers it as a proper AMD module. The shim option is only for code which is not a proper AMD module.
Now, the define in Bootbox does this:
define(["jquery"], factory);
It sets a dependency on jQuery, but that is wrong, because in fact Bootbox also depends on Bootstrap being present. So we need to fix this. The following shows how you can fix it. You can use a map configuration option so that when Bootbox requires jQuery, it gets Bootstrap. And you set a shim for Bootstrap so that, in addition to having a dependency on jQuery, its module value is the same as jQuery ($).
Without the map setup, there's no guarantee that Bootstrap will load before Bootbox and you'll be facing a race condition: sometimes it'll work, sometimes not.
requirejs.config({
baseUrl: ".",
paths: {
jquery: "//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min",
bootstrap: "//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min",
bootbox: "//github.com/makeusabrew/bootbox/releases/download/v4.4.0/bootbox.min"
},
shim: {
"bootstrap": {
"deps": ["jquery"],
// We set bootstrap up so that when we require it, the value with get is just $.
// This enables the map below.
"exports": "$"
},
},
map: {
// When bootbox requires jquery, give it bootstrap instead. This makes it so that
// bootstrap is **necessarily** loaded before bootbox.
bootbox: {
jquery: "bootstrap",
},
}
});
require(["jquery", "bootbox"], function($, bootbox) {
$(function(jquery) {
bootbox.alert("bla");
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.5/require.min.js"></script>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />

How to make a Sublime Text snippet work with Emmet installed

I am trying to make a snippet in Sublime Text 3 that only applies to CSS files. This is the snippet I have:
<snippet>
<content><![CDATA[/*
Theme Name: ${1:Theme name here and so on...}
Theme URI:
Author:
Author URI:
Description:
Version: 1.0.0
License:
License URI:
Text Domain:
Tags:
*/]]></content>
<tabTrigger>xyz</tabTrigger>
<scope>source.css</scope>
</snippet>
The problem is if I open a CSS file, type xyz and hit tab all I will get is xyz: ;. So it seems as if Sublime Text has already assigned the tab to insert : ; instead of my snippet.
This problem does not occur if I remove the plugin package Emmet.
How can I get this snippet to work?
The documentation at http://github.com/sergeche/emmet-sublime#tab-key-handler, suggests that it should be possible to get snippets to work in CSS files with Emmet enabled by adding the following preference in your Emmet preferences file:
"disabled_single_snippet_for_scopes": "source.css"
Since you're already using Emmet, consider using an Emmet snippet instead.
{
"css": {
"filters": "css",
"profile": "css",
"snippets": {
"xyz": "/*\nTheme Name: ${1:Theme name here and so on...}\nTheme URI: \nAuthor: \nAuthor URI: \nDescription: \nVersion: 1.0.0\nLicense: \nLicense URI: \nText Domain: \nTags: \n*/"
}
}
}

Should requirejs be included in the main built file when using the requirejs bundles option

I'm running into an issue when using the require bundles option. If the main built file has requirejs inside of it everything works fine until I try to load a file from a different bundle. The bundled file is retrieved but then throws an "define is undefined" error. The only way I have been able to get the bundle to load is to make sure requirejs is not in the main-built file or the pm.js and then to load requirejs with a script tag and use the data-main attribute, but this doesn't seem right.
So something like this initially works when requirejs is included in main-built.js (site loads fine), but I get the "define is undefined" error when pm.js bundle loads
<script type="text/javascript" src="~/dist/main-built.js"></script>
requirejs.config({
bundles: {
'pm': ['pm/dashboard', 'text!pm/dashboard.html']
}
});
This is how I ended up getting it to work, but doesn't seem right.
<script type="text/javascript" src="~/scripts/require.js" data-main="dist/main-debug")"></script>
This durandal task creates the main-built file
durandal: {
main: {
src: ["app/**/*.*", "scripts/durandal/**/*.*", "!app/mockup/**/*.*", "!app/performancemanagement/**/*.*"],
options: {
//name: "scripts/require",
name: "",
baseUrl: requireConfig.baseUrl,
paths: mixIn({}, requireConfig.paths, { "require": "scripts/require.js" }),
exclude: ["jquery", "knockout", "toastr", "moment", "underscore", "amplify"],
optimize: "none",
out: "dist/main-debug.js"
}
},
},
This task builds the pm.js bundle
requirejs: {
compile: {
options: {
include: generateFileList("app/pm", "**/*.*", false, false),
//exclude: ["jquery", "knockout", "toastr", "moment", "underscore", "amplify", "preferenceconstants", "constants", "config", "utility/koutilities", "scripts/logger", "base/viewmodel"]
// .concat(generateFileList("scripts/durandal", "**/*.js", false))
// .concat(generateFileList("app/dataservice", "**/*.js", false))
// .concat(generateFileList("app/model", "**/*.js", false))
// .concat(generateFileList("app/reports", "**/*.js", false)),
baseUrl: "app/",
name: "",
paths: mixIn({}, requireConfig.paths, { "almond": "scripts/almond-custom.js" }),
optimize: 'none',
inlineText: true,
pragmas: {
build: true
},
stubModules: ['text'],
out: "dist/pm.js"
}
}
}
The pm.js bundle gets downloaded and executed when anything in main-built requires it, right now its being done by the router in Durandal, but I'm pretty sure Durandal has nothing to do with the issue.
This appears suspicious in your main file build:
paths: mixIn({}, requireConfig.paths, { "require": "scripts/require.js" }),
I'm not sure what the mixIn bit does as this is not stock RequireJS code, but you seem to want to include RequireJS in the build under the name require, which is definitely wrong. The documentation says:
If you want to include require.js with the main.js source, you can use this kind of command:
node ../../r.js -o baseUrl=. paths.requireLib=../../require name=main include=requireLib out=main-built.js
Since "require" is a reserved dependency name, you create a "requireLib" dependency and map it to the require.js file.

Resources