Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"This operation is insecure" when using class properties as key

I have a custom FileArgument class that I'm using to store information about an uploaded file:

export class FileArgument {
  name: string;
  path: string;
  file: File;
}

My upload works fine and the server then returns the path where the file was uploaded. I then want to store this path in a dictionary using a previously set fileArgument.name as key. Below is a simplified overview of my component. onSubmit() is where the action is happening:

export class InputModuleComponent {
    private vsmodule: InputModule;
    private moduleArguments = {};
    private fileArgument: FileArgument = new FileArgument();

    @Input()
    module: InputModule;

    constructor(private inputModuleService: InputModuleService) {}

    onSubmit(): void {
        this.inputModuleService.postFile(this.fileArgument.file).subscribe(
            response => {
                this.moduleArguments[this.fileArgument.name] = response.filename;
                console.log(this.moduleArguments);
            },
            error => {}
        );
    }

    onFileChange(event): void {
        this.fileArgument.file = event.originalTarget.files[0];
        this.fileArgument.name = event.originalTarget.id;
    }
}

Line 14 above (this.moduleArguments[this.fileArgument.name] = response.filename;) causes the following error in Firefox:

EXCEPTION: Uncaught (in promise): SecurityError: The operation is insecure.

and in Chrome:

core.umd.js:5995 EXCEPTION: Uncaught (in promise): InvalidStateError: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string.

If I replace that line with, for example:

this.moduleArguments['hello'] = response.filename;

I don't get any errors. The error clearly comes from using fileArgument.name as a dict key, but I have no idea why.

EDIT: The postFile() method from my service is below:

postFile (file: File): Observable<any> {
    console.log('input-module.service - postFile()');
    var url = this.uploadURL;

    return Observable.create(observer => {
        var formData: FormData = new FormData()
        var xhr: XMLHttpRequest = new XMLHttpRequest();

        formData.append("upload", file, file.name);

        xhr.onreadystatechange = () => {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {
                    observer.next(JSON.parse(xhr.response));
                    observer.complete();
                } else {
                observer.error(xhr.response);
                }
            }
        };

        xhr.open('POST', url, true);
        xhr.send(formData);
    });
}

The component HTML:

<a (click)="modal.open()">
    {{vsmodule.displayName}}
</a>

<modal #modal>
    <form (ngSubmit)="onSubmit()">
        <modal-header [show-close]="true">
            <h4 class="modal-title">Input Module - {{vsmodule.displayName}}</h4>
        </modal-header>

        <modal-body>
            <p>{{vsmodule.description}}</p>
            <hr>
                <ul>
                    <li *ngFor="let arg of vsmodule.args; let i = index">
                        <fieldset *ngIf="arg.type == 'file'">
                            <label>{{ arg.displayName }}</label>
                            <input 
                                name="{{arg.name}}" 
                                id="{{ arg.name }}"
                                type="file"

                                [(ngModel)]="moduleArguments[arg.name]"
                                (change)="onFileChange($event)" 
                            >
                            <p>{{ arg.description }}<p>
                        </fieldset>
                    </li>
                </ul>
        </modal-body>

        <modal-footer>
            <button type="button" class="btn btn-default" data-dismiss="modal" (click)="modal.dismiss()">Dismiss</button>
            <button type="submit" class="btn btn-primary">Run</button>
        </modal-footer>
    </form>
</modal>
like image 590
Juicy Avatar asked Sep 10 '16 15:09

Juicy


1 Answers

In onChange, fileArgument.name is set to the value of event.originalTarget.id - the id of an actual HTML element in the page

And chrome error is saying:

Failed to set the 'value' property on 'HTMLInputElement'

Edit since you added the html - you have bound the 'moduleArguements' property to the file input element's ngmodel - as a result, changing that value will cause angular to try and modify the value property on the file input which is not permitted.

What is the purpose of updating that value? Is it just to feedback to the user?

If you remove the ngModel binding from the input element it should work - you are using the onFileChange event to capture the new filename anyway (although in the controller it is just onChange?)

like image 192
Chris Simon Avatar answered Nov 14 '22 15:11

Chris Simon