5

What I've got

I'm building a personal blog app with Angular 2. I have blog posts in a JSON file which is served from my server.

// Single post route
apiRouter.route("/post/:id")
    // Get a specific post
    .get((req: express.Request, res: express.Response) => {
        let post = blogData.posts.find(post => post.date === Number(req.params.id));
        res.json(post);
    })
);

Individual entries in the JSON blog data file look like this:

"posts": [
  {
    "title": "Some Post's Title",
    "body": "Some post's body.",
    "date": 1481582451092,
    "headerImageName": ""
  },
  { ... }, ...
]

In my webapp I want to have a single "Blog Post" typescript component that displays an individual post when a visitor is on a route which maps to a single post.

I've defined a simple post data class like this:

export class PostData {
    body: string;
    date: number;
    imageFileName: string;
    title: string;
}

When displaying the post body I pass it through this pipe:

@Pipe({
    name: "trustPipe"
})
export class TrustPipe implements PipeTransform {

    constructor(@Inject(DomSanitizer) private sanitizer: DomSanitizer) { }

    transform(html: string): SafeHtml {
        return this.sanitizer.bypassSecurityTrustHtml(html);
    }
} 

In order to display it, I've written the following component:

import { TrustPipe } from "./trust.pipe";

@Component({
    selector: "active-component",
    template: `
    <div class="card">
        <div *ngIf="post">
            <div class="card-title">
                <span>{{ post.title }}</span>
            </div>
            <div [innerHTML]="post.body | trustPipe"></div>
        </div>
    </div>`,
    styleUrls: ["styles/post.component.css", "styles/card.css"]
})
export class PostComponent implements OnInit {
  
    // Post is a superclass to PostData, it just provides
    // some helper functions on the base class, such as truncation
    // and a means of formatting dates
    post: Post;

    constructor(
        @Inject(BlogService) private blogService: BlogService,
        @Inject(ActivatedRoute) private activatedRoute: ActivatedRoute
    ) { }

    ngOnInit(): void {
        this.activatedRoute.params.forEach((params: Params) => {
            const id: number = +params["id"];
            this.blogService
                .getPost(id)
                .then(data => this.post = new Post(data));
        });
    }
}

What Does this all do?

With that out of the way, the important takeaway is that I have some variant string (JSON for a post's body) which represents a section of HTML I'd like to insert as a child to some DOM element. To do so I used the [innerHTML] attribute and wrote an Angular Pipe that uses bypassSecurityTrustHtml for trusting the string as safe HTML.

What happens?

Script tags don't execute. Say I've written a blog post which has something embedded in it - in my case it's likely a Github Gist, Instagram photo, or Google photos album. I found that this is true - script tags don't execute - and a means of using Javascript to circumvent it, but I want to know if angular has a means of inserting HTML like I'm trying. I have seen usage of ComponentFactory but I don't know if this is what I want. I'm guessing this will also stop me from using routerLinks in my post's bodies. I could write a child component for the post body, but then how do I dynamically swap out templates?

Questions

a) Why does Angular stop scripts from running?

b) Any other means to get scripts to run?

c) Should I use a different design pattern for this - serving posts as HTML for example?

1

1 Answer 1

2

a) Security and in particular protection against XSS - https://angular.io/docs/ts/latest/guide/security.html

b) Yes but but be very careful - https://angular.io/docs/ts/latest/guide/security.html#!#bypass-security-apis

Have you tried bypassing the security apis in your component instead of a pipe? Also what security context are you using?

c) Can you parse the blog post and save it in a safe format or do you really want to allow any js to run on your website?

Sign up to request clarification or add additional context in comments.

3 Comments

a) Ahh yes duh. XSS - I've studied that in my security engineering course. b) Yep, that's what I'm using, still no script execution. c) I'm the one writing the posts, so I can do anything. What do you suggest?
a) it is as simple as that b) Can you post the code where you are bypassing the security apis? c) Sorry I don't know :)
Added in the pipe transform to the original question

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.